mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 12:11:13 +00:00
Add monkeyaudio plugin
Original commit message from CVS: Add monkeyaudio plugin
This commit is contained in:
parent
e4ef8a39de
commit
c1a4db611b
57 changed files with 8631 additions and 1 deletions
|
@ -238,7 +238,7 @@ GST_PLUGINS_ALL="\
|
|||
dnl see if we can build C++ plug-ins
|
||||
if test "x$HAVE_CXX" = "xyes"; then
|
||||
GST_PLUGINS_ALL="$GST_PLUGINS_ALL \
|
||||
modplug"
|
||||
modplug monkeyaudio"
|
||||
else
|
||||
AC_MSG_WARN([Not compiling plug-ins requiring C++ compiler])
|
||||
fi
|
||||
|
@ -1054,6 +1054,8 @@ gst/mpegtypes/Makefile
|
|||
gst/modplug/Makefile
|
||||
gst/modplug/libmodplug/Makefile
|
||||
gst/monoscope/Makefile
|
||||
gst/monkeyaudio/Makefile
|
||||
gst/monkeyaudio/libmonkeyaudio/Makefile
|
||||
gst/oneton/Makefile
|
||||
gst/passthrough/Makefile
|
||||
gst/playondemand/Makefile
|
||||
|
|
17
gst/monkeyaudio/LICENSE
Normal file
17
gst/monkeyaudio/LICENSE
Normal file
|
@ -0,0 +1,17 @@
|
|||
Monkey's Audio SDK (3.96b1)
|
||||
(last updated March 16, 2002)
|
||||
|
||||
|
||||
This SDK provides the tools to incorporate Monkey's Audio into your own projects. Cruising through the examples is probably the easiest way to learn how to use everything. If you use C++, it's recommended that you simply statically link to maclib.lib. If you use another language or want dynamic linkage, you can use the C-style interface of the dll. (see Decompress\Sample 3 for an example)
|
||||
|
||||
If you make any improvements or make any projects of your own that you'd like to add, just let let me know. Also, any help or ideas on how to make the SDK better or more clear would be great.
|
||||
|
||||
If you link against the included libraries (dynamically or statically), please let me know. As always you can reach me at email @ monkeysaudio.com
|
||||
|
||||
Also, much of the Monkey's Audio source code is now included with the SDK. Explore the "Source" directory for more information.
|
||||
|
||||
Thanks and good luck :)
|
||||
|
||||
- All materials and programs copyrighted ©2000-2002 by Matthew T. Ashland -
|
||||
|
||||
- All rights reserved. -
|
25
gst/monkeyaudio/Makefile.am
Normal file
25
gst/monkeyaudio/Makefile.am
Normal file
|
@ -0,0 +1,25 @@
|
|||
SUBDIRS=libmonkeyaudio .
|
||||
|
||||
plugindir = $(libdir)/gstreamer-@GST_MAJORMINOR@
|
||||
|
||||
plugin_LTLIBRARIES = libgstmonkeyaudio.la
|
||||
|
||||
libgstmonkeyaudio_la_SOURCES = monkey_io.cc gstmonkeyaudio.cc gstmonkeydec.cc gstmonkeyenc.cc
|
||||
libgstmonkeyaudio_la_CFLAGS = $(GST_CFLAGS)
|
||||
libgstmonkeyaudio_la_CXXFLAGS = $(GST_CFLAGS)
|
||||
libgstmonkeyaudio_la_LIBADD = $(top_builddir)/gst/monkeyaudio/libmonkeyaudio/libmonkeyaudio.la
|
||||
# we add stdc++ because it'll be used by C programs
|
||||
libgstmonkeyaudio_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) -lstdc++
|
||||
|
||||
noinst_HEADERS = gstmonkeyaudio.h gstmonkeydec.h
|
||||
|
||||
# this is the silliest hack I ever did, but for some reason some dependency
|
||||
# tracking is not able to figure out that the actual file is gstmonkeyaudio.cc
|
||||
# I appreciate any help into fixing this mess definitively
|
||||
# I suspect a libtool bug, because in the end it doesn't even *use* the .c
|
||||
# file; my libtool version when seeing this bug was 1.4.2
|
||||
#gstmonkeyaudio.c: gstmonkeyaudio.cc
|
||||
# cp $(srcdir)/gstmonkeyaudio.cc gstmonkeyaudio.c
|
||||
|
||||
#monkeyaudio_types.c: monkeyaudio_types.cc
|
||||
# cp $(srcdir)/monkeyaudio_types.cc monkeyaudio_types.c
|
149
gst/monkeyaudio/gstmonkeyaudio.cc
Normal file
149
gst/monkeyaudio/gstmonkeyaudio.cc
Normal file
|
@ -0,0 +1,149 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
||||
*
|
||||
* 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <gst/gst.h>
|
||||
|
||||
#include "gstmonkeydec.h"
|
||||
#include "gstmonkeyenc.h"
|
||||
|
||||
extern GstElementDetails gst_monkeydec_details;
|
||||
extern GstElementDetails gst_monkeyenc_details;
|
||||
|
||||
static GstCaps* monkey_type_find (GstBuffer *buf, gpointer priv);
|
||||
|
||||
GstPadTemplate *monkeydec_sink_template, *monkeydec_src_template;
|
||||
GstPadTemplate *monkeyenc_sink_template, *monkeyenc_src_template;
|
||||
|
||||
static GstCaps*
|
||||
monkey_caps_factory (void)
|
||||
{
|
||||
return gst_caps_new ("monkey_application",
|
||||
"application/x-ape",
|
||||
NULL
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
static GstCaps*
|
||||
raw_caps_factory (void)
|
||||
{
|
||||
return gst_caps_new ("monkey_raw",
|
||||
"audio/raw",
|
||||
gst_props_new (
|
||||
"format", GST_PROPS_STRING ("int"),
|
||||
"law", GST_PROPS_INT (0),
|
||||
"endianness", GST_PROPS_INT (G_BYTE_ORDER),
|
||||
"signed", GST_PROPS_BOOLEAN (TRUE),
|
||||
"width", GST_PROPS_INT (16),
|
||||
"depth", GST_PROPS_INT (16),
|
||||
"rate", GST_PROPS_INT_RANGE (11025, 44100),
|
||||
"channels", GST_PROPS_INT_RANGE (1, 2),
|
||||
NULL
|
||||
));
|
||||
}
|
||||
|
||||
static GstCaps*
|
||||
wav_caps_factory (void)
|
||||
{
|
||||
return gst_caps_new ("monkey_wav",
|
||||
"audio/x-wav",
|
||||
NULL );
|
||||
}
|
||||
|
||||
|
||||
static GstTypeDefinition monkeydefinition = {
|
||||
"monkey_application/x-ape", "application/x-ape", ".ape", monkey_type_find,
|
||||
};
|
||||
|
||||
|
||||
static GstCaps*
|
||||
monkey_type_find (GstBuffer *buf, gpointer priv)
|
||||
{
|
||||
if (strncmp ((gchar *)GST_BUFFER_DATA (buf), "MAC ", 4) != 0)
|
||||
return NULL;
|
||||
|
||||
return gst_caps_new ("monkey_type_find", "application/x-ape", NULL);
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
plugin_init (GModule * module, GstPlugin * plugin)
|
||||
{
|
||||
GstElementFactory *monkey_dec, *monkey_enc;
|
||||
GstTypeFactory *type;
|
||||
GstCaps *raw_caps, *wav_caps, *monkey_caps;
|
||||
|
||||
/* this filter needs the bytestream package */
|
||||
if (!gst_library_load ("gstbytestream"))
|
||||
return FALSE;
|
||||
|
||||
raw_caps = raw_caps_factory ();
|
||||
monkey_caps = monkey_caps_factory ();
|
||||
wav_caps = wav_caps_factory ();
|
||||
|
||||
/* create an elementfactory for the monkeydec element */
|
||||
monkey_dec = gst_element_factory_new ("monkeydec", GST_TYPE_MONKEYDEC, &gst_monkeydec_details);
|
||||
g_return_val_if_fail(monkey_dec != NULL, FALSE);
|
||||
|
||||
/* register sink pads */
|
||||
monkeydec_sink_template = gst_pad_template_new ("sink", GST_PAD_SINK,
|
||||
GST_PAD_ALWAYS,
|
||||
monkey_caps, NULL);
|
||||
gst_element_factory_add_pad_template (monkey_dec, monkeydec_sink_template);
|
||||
|
||||
|
||||
/* register src pads */
|
||||
monkeydec_src_template = gst_pad_template_new ("src", GST_PAD_SRC,
|
||||
GST_PAD_ALWAYS,
|
||||
raw_caps, NULL);
|
||||
gst_element_factory_add_pad_template (monkey_dec, monkeydec_src_template);
|
||||
|
||||
gst_element_factory_set_rank (monkey_dec, GST_ELEMENT_RANK_PRIMARY);
|
||||
gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (monkey_dec));
|
||||
|
||||
|
||||
/* create an elementfactory for the monkeydec element */
|
||||
monkey_enc = gst_element_factory_new ("monkeyenc", GST_TYPE_MONKEYENC, &gst_monkeyenc_details);
|
||||
g_return_val_if_fail(monkey_enc != NULL, FALSE);
|
||||
|
||||
/* register sink pads */
|
||||
monkeyenc_sink_template = gst_pad_template_new ("sink", GST_PAD_SINK,
|
||||
GST_PAD_ALWAYS,
|
||||
wav_caps, NULL);
|
||||
gst_element_factory_add_pad_template (monkey_enc, monkeyenc_sink_template);
|
||||
|
||||
|
||||
/* register src pads */
|
||||
monkeyenc_src_template = gst_pad_template_new ("src", GST_PAD_SRC,
|
||||
GST_PAD_ALWAYS,
|
||||
monkey_caps, NULL);
|
||||
gst_element_factory_add_pad_template (monkey_enc, monkeyenc_src_template);
|
||||
|
||||
gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (monkey_enc));
|
||||
|
||||
|
||||
type = gst_type_factory_new (&monkeydefinition);
|
||||
gst_plugin_add_feature (plugin, GST_PLUGIN_FEATURE (type));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
GstPluginDesc plugin_desc = {
|
||||
GST_VERSION_MAJOR,
|
||||
GST_VERSION_MINOR,
|
||||
"monkey audio",
|
||||
plugin_init
|
||||
};
|
38
gst/monkeyaudio/gstmonkeyaudio.h
Normal file
38
gst/monkeyaudio/gstmonkeyaudio.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
||||
*
|
||||
* Filter:
|
||||
* Copyright (C) 2000 Donald A. Graft
|
||||
*
|
||||
* 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __GST_MONKEYAUDIO_H__
|
||||
#define __GST_MONKEYAUDIO_H__
|
||||
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#include <config.h>
|
||||
#include <gst/gst.h>
|
||||
|
||||
GType gst_monkeyenc_get_type (void);
|
||||
extern GstElementDetails gst_monkeyenc_details;
|
||||
|
||||
extern GstPadTemplate *gst_monkey_sink_factory ();
|
||||
/*extern GstPadTemplate *gst_monkey_src_factory ();*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif
|
370
gst/monkeyaudio/gstmonkeydec.cc
Normal file
370
gst/monkeyaudio/gstmonkeydec.cc
Normal file
|
@ -0,0 +1,370 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
||||
*
|
||||
* Filter:
|
||||
* Copyright (C) 2000 Donald A. Graft
|
||||
*
|
||||
* 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <gst/gst.h>
|
||||
|
||||
#include "gstmonkeydec.h"
|
||||
|
||||
|
||||
GstElementDetails gst_monkeydec_details = {
|
||||
"MonkeyAudio decoder",
|
||||
"Codec/Audio/Decoder",
|
||||
"Free to use",
|
||||
"Decode MonkeyAudio audio stream (.ape)",
|
||||
VERSION,
|
||||
"Jeremy SIMON <jsimon13@yahoo.fr>",
|
||||
"(C) 2002 Matthew T. Ashland",
|
||||
};
|
||||
|
||||
|
||||
/* Filter signals and args */
|
||||
enum
|
||||
{
|
||||
/* FILL ME */
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
ARG_0
|
||||
};
|
||||
|
||||
static void gst_monkeydec_class_init (GstMonkeyDecClass *klass);
|
||||
static void gst_monkeydec_init (GstMonkeyDec *monkeydec);
|
||||
static void gst_monkeydec_loop (GstElement *element);
|
||||
static gboolean
|
||||
gst_monkeydec_src_event (GstPad *pad, GstEvent *event);
|
||||
static gboolean
|
||||
gst_monkeydec_src_query (GstPad *pad, GstQueryType type,
|
||||
GstFormat *format, gint64 *value);
|
||||
static const GstQueryType*
|
||||
gst_monkeydec_get_query_types (GstPad *pad);
|
||||
static const GstFormat*
|
||||
gst_monkeydec_get_formats (GstPad *pad);
|
||||
static GstElementStateReturn
|
||||
gst_monkeydec_change_state (GstElement *element);
|
||||
|
||||
|
||||
static GstElementClass *parent_class = NULL;
|
||||
|
||||
GType gst_monkeydec_get_type (void)
|
||||
{
|
||||
static GType monkeydec_type = 0;
|
||||
|
||||
if (!monkeydec_type) {
|
||||
static const GTypeInfo monkeydec_info = {
|
||||
sizeof (GstMonkeyDecClass), NULL,
|
||||
NULL,
|
||||
(GClassInitFunc) gst_monkeydec_class_init,
|
||||
NULL,
|
||||
NULL,
|
||||
sizeof (GstMonkeyDec),
|
||||
0,
|
||||
(GInstanceInitFunc) gst_monkeydec_init,
|
||||
};
|
||||
|
||||
monkeydec_type = g_type_register_static (GST_TYPE_ELEMENT, "GstMonkeyDec", &monkeydec_info, (GTypeFlags)0);
|
||||
}
|
||||
return monkeydec_type;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gst_monkeydec_class_init (GstMonkeyDecClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
GstElementClass *gstelement_class;
|
||||
|
||||
gobject_class = (GObjectClass *) klass;
|
||||
gstelement_class = (GstElementClass *) klass;
|
||||
|
||||
gstelement_class->change_state = gst_monkeydec_change_state;
|
||||
|
||||
parent_class = GST_ELEMENT_CLASS( g_type_class_ref(GST_TYPE_ELEMENT));
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gst_monkeydec_init (GstMonkeyDec * monkeydec)
|
||||
{
|
||||
monkeydec->sinkpad = gst_pad_new_from_template (monkeydec_sink_template, "sink");
|
||||
gst_element_add_pad (GST_ELEMENT (monkeydec), monkeydec->sinkpad);
|
||||
|
||||
monkeydec->srcpad = gst_pad_new_from_template (monkeydec_src_template, "src");
|
||||
gst_element_add_pad (GST_ELEMENT (monkeydec), monkeydec->srcpad);
|
||||
|
||||
gst_element_set_loop_function (GST_ELEMENT (monkeydec), gst_monkeydec_loop);
|
||||
|
||||
gst_pad_set_event_function (monkeydec->srcpad, (GstPadEventFunction)(gst_monkeydec_src_event));
|
||||
gst_pad_set_query_function (monkeydec->srcpad, gst_monkeydec_src_query);
|
||||
gst_pad_set_query_type_function (monkeydec->srcpad, (GstPadQueryTypeFunction)(gst_monkeydec_get_query_types));
|
||||
gst_pad_set_formats_function (monkeydec->srcpad, (GstPadFormatsFunction)(gst_monkeydec_get_formats));
|
||||
}
|
||||
|
||||
|
||||
static const GstFormat*
|
||||
gst_monkeydec_get_formats (GstPad *pad)
|
||||
{
|
||||
static const GstFormat src_formats[] = {
|
||||
/* GST_FORMAT_BYTES,
|
||||
GST_FORMAT_UNITS,*/
|
||||
GST_FORMAT_TIME,
|
||||
(GstFormat)0
|
||||
};
|
||||
static const GstFormat sink_formats[] = {
|
||||
/*GST_FORMAT_BYTES,*/
|
||||
GST_FORMAT_TIME,
|
||||
(GstFormat)0
|
||||
};
|
||||
|
||||
return (GST_PAD_IS_SRC (pad) ? src_formats : sink_formats);
|
||||
}
|
||||
|
||||
|
||||
static const GstQueryType*
|
||||
gst_monkeydec_get_query_types (GstPad *pad)
|
||||
{
|
||||
static const GstQueryType gst_monkeydec_src_query_types[] = {
|
||||
GST_QUERY_TOTAL,
|
||||
GST_QUERY_POSITION,
|
||||
(GstQueryType)0
|
||||
};
|
||||
|
||||
return gst_monkeydec_src_query_types;
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
gst_monkeydec_src_query (GstPad *pad, GstQueryType type,
|
||||
GstFormat *format, gint64 *value)
|
||||
{
|
||||
gboolean res = TRUE;
|
||||
GstMonkeyDec *monkeydec;
|
||||
|
||||
monkeydec = GST_MONKEYDEC (gst_pad_get_parent (pad));
|
||||
|
||||
switch (type) {
|
||||
case GST_QUERY_TOTAL:
|
||||
switch (*format) {
|
||||
case GST_FORMAT_DEFAULT:
|
||||
*format = GST_FORMAT_TIME;
|
||||
case GST_FORMAT_TIME:
|
||||
*value = monkeydec->decomp->GetInfo (APE_DECOMPRESS_LENGTH_MS) * 1000000LL;
|
||||
g_print ("Song lentgh : %lld\n", *value);
|
||||
break;
|
||||
default:
|
||||
res = FALSE;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case GST_QUERY_POSITION:
|
||||
switch (*format) {
|
||||
case GST_FORMAT_DEFAULT:
|
||||
*format = GST_FORMAT_TIME;
|
||||
default:
|
||||
*value = monkeydec->decomp->GetInfo (APE_DECOMPRESS_CURRENT_MS) * 1000000LL;
|
||||
//g_print ("Song position : %lld\n", *value);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
static gboolean
|
||||
gst_monkeydec_src_event (GstPad *pad, GstEvent *event)
|
||||
{
|
||||
gboolean res = TRUE;
|
||||
GstMonkeyDec *monkeydec;
|
||||
|
||||
monkeydec = GST_MONKEYDEC (gst_pad_get_parent (pad));
|
||||
|
||||
switch (GST_EVENT_TYPE (event)) {
|
||||
/* the all-formats seek logic */
|
||||
case GST_EVENT_SEEK:
|
||||
{
|
||||
gboolean flush;
|
||||
GstFormat format;
|
||||
|
||||
format = GST_FORMAT_TIME;
|
||||
|
||||
/* shave off the flush flag, we'll need it later */
|
||||
flush = GST_EVENT_SEEK_FLAGS (event) & GST_SEEK_FLAG_FLUSH;
|
||||
|
||||
monkeydec->seek_to = GST_EVENT_SEEK_OFFSET (event) * monkeydec->frequency / GST_SECOND;
|
||||
g_print ("Seek to : %lld\n", monkeydec->seek_to);
|
||||
|
||||
monkeydec->io->need_discont = TRUE;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
res = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
gst_event_unref (event);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_monkeydec_loop (GstElement *element)
|
||||
{
|
||||
GstMonkeyDec *monkeydec;
|
||||
gint blocks_retrieved;
|
||||
GstBuffer *buffer_out;
|
||||
GstFormat format;
|
||||
gint64 timestamp;
|
||||
gint retval;
|
||||
|
||||
g_return_if_fail (element != NULL);
|
||||
g_return_if_fail (GST_IS_MONKEYDEC (element));
|
||||
|
||||
monkeydec = GST_MONKEYDEC (element);
|
||||
|
||||
if (!GST_PAD_IS_USABLE (monkeydec->srcpad))
|
||||
return;
|
||||
|
||||
if (monkeydec->init)
|
||||
{
|
||||
monkeydec->io = new sinkpad_CIO;
|
||||
monkeydec->io->bs = gst_bytestream_new (monkeydec->sinkpad);
|
||||
if (monkeydec->io->bs == NULL)
|
||||
{
|
||||
gst_element_error(element, "Failed to initiliaze bytestream from sinkpad");
|
||||
return;
|
||||
}
|
||||
|
||||
monkeydec->io->sinkpad = monkeydec->sinkpad;
|
||||
|
||||
monkeydec->io->Open ("");
|
||||
monkeydec->decomp = CreateIAPEDecompressEx (monkeydec->io, &retval);
|
||||
if (monkeydec->decomp == NULL)
|
||||
{
|
||||
gst_element_error(element, "Failed to initiliaze MonkeyAudio decoder engine : %d", retval);
|
||||
return;
|
||||
}
|
||||
|
||||
monkeydec->channels = monkeydec->decomp->GetInfo (APE_INFO_CHANNELS);
|
||||
monkeydec->frequency = monkeydec->decomp->GetInfo (APE_INFO_SAMPLE_RATE);
|
||||
monkeydec->depth = monkeydec->decomp->GetInfo (APE_INFO_BITS_PER_SAMPLE);
|
||||
|
||||
monkeydec->io->eos = FALSE;
|
||||
|
||||
monkeydec->total_samples = 0;
|
||||
monkeydec->io->need_discont = FALSE;
|
||||
monkeydec->seek_to = 0;
|
||||
|
||||
monkeydec->init = FALSE;
|
||||
}
|
||||
|
||||
buffer_out = gst_buffer_new_and_alloc (1024 * monkeydec->decomp->GetInfo(APE_INFO_BLOCK_ALIGN));
|
||||
|
||||
if (monkeydec->seek_to != 0)
|
||||
{
|
||||
monkeydec->decomp->Seek (monkeydec->seek_to);
|
||||
monkeydec->seek_to = 0;
|
||||
}
|
||||
|
||||
format = GST_FORMAT_TIME;
|
||||
gst_monkeydec_src_query (monkeydec->srcpad, GST_QUERY_POSITION, &format, ×tamp);
|
||||
|
||||
|
||||
if (monkeydec->io->need_discont)
|
||||
{
|
||||
monkeydec->io->need_discont = FALSE;
|
||||
|
||||
/* if the pad is not usable, don't push it out */
|
||||
if (GST_PAD_IS_USABLE (monkeydec->srcpad))
|
||||
{
|
||||
GstEvent *discont;
|
||||
|
||||
discont = gst_event_new_discontinuous (FALSE, GST_FORMAT_TIME, timestamp, NULL);
|
||||
|
||||
gst_pad_push (monkeydec->srcpad, GST_BUFFER (discont));
|
||||
}
|
||||
}
|
||||
|
||||
monkeydec->decomp->GetData((char *) GST_BUFFER_DATA (buffer_out), 1024, &blocks_retrieved);
|
||||
|
||||
GST_BUFFER_SIZE (buffer_out) = blocks_retrieved * monkeydec->decomp->GetInfo(APE_INFO_BLOCK_ALIGN);
|
||||
GST_BUFFER_TIMESTAMP (buffer_out) = timestamp;
|
||||
|
||||
|
||||
if (!GST_PAD_CAPS (monkeydec->srcpad)) {
|
||||
gst_pad_try_set_caps (monkeydec->srcpad,
|
||||
GST_CAPS_NEW (
|
||||
"monkeydec_caps",
|
||||
"audio/raw",
|
||||
"format", GST_PROPS_STRING ("int"),
|
||||
"law", GST_PROPS_INT (0),
|
||||
"endianness", GST_PROPS_INT (G_BYTE_ORDER),
|
||||
"signed", GST_PROPS_BOOLEAN (TRUE),
|
||||
"width", GST_PROPS_INT (monkeydec->depth),
|
||||
"depth", GST_PROPS_INT (monkeydec->depth),
|
||||
"rate", GST_PROPS_INT (monkeydec->frequency),
|
||||
"channels", GST_PROPS_INT (monkeydec->channels)
|
||||
));
|
||||
}
|
||||
|
||||
gst_pad_push (monkeydec->srcpad, buffer_out);
|
||||
|
||||
if (monkeydec->io->eos)
|
||||
{
|
||||
GstEvent *event;
|
||||
|
||||
event = gst_event_new (GST_EVENT_EOS);
|
||||
gst_pad_push (monkeydec->srcpad, GST_BUFFER (event));
|
||||
gst_element_set_eos (element);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static GstElementStateReturn
|
||||
gst_monkeydec_change_state (GstElement *element)
|
||||
{
|
||||
GstMonkeyDec *monkeydec;
|
||||
|
||||
monkeydec = GST_MONKEYDEC (element);
|
||||
|
||||
switch (GST_STATE_TRANSITION (element)) {
|
||||
case GST_STATE_NULL_TO_READY:
|
||||
break;
|
||||
case GST_STATE_READY_TO_PAUSED:
|
||||
monkeydec->init = TRUE;
|
||||
break;
|
||||
case GST_STATE_PAUSED_TO_PLAYING:
|
||||
/* do something to get out of the chain function faster */
|
||||
break;
|
||||
case GST_STATE_PLAYING_TO_PAUSED:
|
||||
break;
|
||||
case GST_STATE_PAUSED_TO_READY:
|
||||
break;
|
||||
case GST_STATE_READY_TO_NULL:
|
||||
break;
|
||||
}
|
||||
|
||||
parent_class->change_state (element);
|
||||
|
||||
return GST_STATE_SUCCESS;
|
||||
}
|
78
gst/monkeyaudio/gstmonkeydec.h
Normal file
78
gst/monkeyaudio/gstmonkeydec.h
Normal file
|
@ -0,0 +1,78 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library 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.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __GST_MONKEYDEC_H__
|
||||
#define __GST_MONKEYDEC_H__
|
||||
|
||||
#include "libmonkeyaudio/All.h"
|
||||
#include "libmonkeyaudio/GlobalFunctions.h"
|
||||
#include "libmonkeyaudio/MACLib.h"
|
||||
#include "libmonkeyaudio/IO.h"
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
#include "monkey_io.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
|
||||
#define GST_TYPE_MONKEYDEC (gst_monkeydec_get_type())
|
||||
#define GST_MONKEYDEC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MONKEYDEC,GstMonkeyDec))
|
||||
#define GST_MONKEYDEC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MONKEYDEC,GstMonkeyDec))
|
||||
#define GST_IS_MONKEYDEC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MONKEYDEC))
|
||||
#define GST_IS_MONKEYDEC_CLASS(obj)(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MONKEYDEC))
|
||||
|
||||
typedef struct _GstMonkeyDec GstMonkeyDec;
|
||||
typedef struct _GstMonkeyDecClass GstMonkeyDecClass;
|
||||
|
||||
extern GstPadTemplate *monkeydec_src_template, *monkeydec_sink_template;
|
||||
|
||||
struct _GstMonkeyDec
|
||||
{
|
||||
GstElement element;
|
||||
|
||||
GstPad *sinkpad, *srcpad;
|
||||
gboolean init;
|
||||
guint64 total_samples;
|
||||
guint64 seek_to;
|
||||
guint channels;
|
||||
guint frequency;
|
||||
guint depth;
|
||||
|
||||
IAPEDecompress *decomp;
|
||||
|
||||
sinkpad_CIO *io;
|
||||
};
|
||||
|
||||
struct _GstMonkeyDecClass
|
||||
{
|
||||
GstElementClass parent_class;
|
||||
};
|
||||
|
||||
GType gst_monkeydec_get_type(void);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __GST_MONKEYDEC_H__ */
|
231
gst/monkeyaudio/gstmonkeyenc.cc
Normal file
231
gst/monkeyaudio/gstmonkeyenc.cc
Normal file
|
@ -0,0 +1,231 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
||||
*
|
||||
* Filter:
|
||||
* Copyright (C) 2000 Donald A. Graft
|
||||
*
|
||||
* 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <gst/gst.h>
|
||||
|
||||
#include "gstmonkeyenc.h"
|
||||
|
||||
GstElementDetails gst_monkeyenc_details = {
|
||||
"MonkeyAudio encoder",
|
||||
"Codec/Audio/Encoder",
|
||||
"Free to use",
|
||||
"Encode to MonkeyAudio audio stream (.ape)",
|
||||
VERSION,
|
||||
"Jeremy SIMON <jsimon13@yahoo.fr>",
|
||||
"(C) 2002 Matthew T. Ashland",
|
||||
};
|
||||
|
||||
|
||||
/* Filter signals and args */
|
||||
enum
|
||||
{
|
||||
/* FILL ME */
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
ARG_0
|
||||
};
|
||||
|
||||
|
||||
static void gst_monkeyenc_class_init (GstMonkeyEncClass *klass);
|
||||
static void gst_monkeyenc_init (GstMonkeyEnc *monkeyenc);
|
||||
static void gst_monkeyenc_loop (GstElement *element);
|
||||
|
||||
static GstElementStateReturn
|
||||
gst_monkeyenc_change_state (GstElement *element);
|
||||
|
||||
static GstElementClass *parent_class = NULL;
|
||||
|
||||
GType gst_monkeyenc_get_type (void)
|
||||
{
|
||||
static GType monkeyenc_type = 0;
|
||||
|
||||
if (!monkeyenc_type) {
|
||||
static const GTypeInfo monkeyenc_info = {
|
||||
sizeof (GstMonkeyEncClass), NULL,
|
||||
NULL,
|
||||
(GClassInitFunc) gst_monkeyenc_class_init,
|
||||
NULL,
|
||||
NULL,
|
||||
sizeof (GstMonkeyEnc),
|
||||
0,
|
||||
(GInstanceInitFunc) gst_monkeyenc_init,
|
||||
};
|
||||
|
||||
monkeyenc_type = g_type_register_static (GST_TYPE_ELEMENT, "GstMonkeyEnc", &monkeyenc_info, (GTypeFlags)0);
|
||||
}
|
||||
return monkeyenc_type;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gst_monkeyenc_class_init (GstMonkeyEncClass *klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
GstElementClass *gstelement_class;
|
||||
|
||||
gobject_class = (GObjectClass *) klass;
|
||||
gstelement_class = (GstElementClass *) klass;
|
||||
|
||||
gstelement_class->change_state = gst_monkeyenc_change_state;
|
||||
|
||||
parent_class = GST_ELEMENT_CLASS( g_type_class_ref(GST_TYPE_ELEMENT));
|
||||
}
|
||||
|
||||
/*
|
||||
static GstPadLinkReturn
|
||||
gst_monkeyenc_sinklink (GstPad *pad, GstCaps *caps)
|
||||
{
|
||||
GstMonkeyEnc *monkeyenc;
|
||||
|
||||
monkeyenc = GST_MONKEYENC (gst_pad_get_parent (pad));
|
||||
|
||||
if (!GST_CAPS_IS_FIXED (caps))
|
||||
return GST_PAD_LINK_DELAYED;
|
||||
|
||||
gst_caps_get_int (caps, "channels", &monkeyenc->channels);
|
||||
gst_caps_get_int (caps, "rate", &monkeyenc->rate);
|
||||
gst_caps_get_int (caps, "depth", &monkeyenc->depth);
|
||||
|
||||
monkeyenc->linked = TRUE;
|
||||
|
||||
return GST_PAD_LINK_OK;
|
||||
}*/
|
||||
|
||||
static void
|
||||
gst_monkeyenc_init (GstMonkeyEnc * monkeyenc)
|
||||
{
|
||||
monkeyenc->sinkpad = gst_pad_new_from_template (monkeyenc_sink_template, "sink");
|
||||
gst_element_add_pad (GST_ELEMENT (monkeyenc), monkeyenc->sinkpad);
|
||||
|
||||
monkeyenc->srcpad = gst_pad_new_from_template (monkeyenc_src_template, "src");
|
||||
gst_element_add_pad (GST_ELEMENT (monkeyenc), monkeyenc->srcpad);
|
||||
|
||||
/*gst_pad_set_link_function (monkeyenc->sinkpad, gst_monkeyenc_sinklink);*/
|
||||
|
||||
gst_element_set_loop_function (GST_ELEMENT (monkeyenc), gst_monkeyenc_loop);
|
||||
|
||||
monkeyenc->linked = FALSE;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
gst_monkeyenc_loop (GstElement *element)
|
||||
{
|
||||
GstMonkeyEnc *monkeyenc;
|
||||
gint retval, size;
|
||||
|
||||
g_return_if_fail (element != NULL);
|
||||
g_return_if_fail (GST_IS_MONKEYENC (element));
|
||||
|
||||
monkeyenc = GST_MONKEYENC (element);
|
||||
|
||||
if (!GST_PAD_IS_USABLE (monkeyenc->srcpad))
|
||||
return;
|
||||
|
||||
if (monkeyenc->init)
|
||||
{
|
||||
unsigned char *wav_header;
|
||||
|
||||
monkeyenc->src_io = new srcpad_CIO;
|
||||
monkeyenc->src_io->Open("");
|
||||
monkeyenc->src_io->srcpad = monkeyenc->srcpad;
|
||||
|
||||
monkeyenc->sink_io = new sinkpad_CIO;
|
||||
monkeyenc->sink_io->sinkpad = monkeyenc->sinkpad;
|
||||
monkeyenc->sink_io->bs = gst_bytestream_new (monkeyenc->sinkpad);
|
||||
if (monkeyenc->sink_io->bs == NULL)
|
||||
{
|
||||
gst_element_error(element, "Failed to initiliaze bytestream from sinkpad");
|
||||
return;
|
||||
}
|
||||
|
||||
monkeyenc->inputsrc = new CWAVInputSource (monkeyenc->sink_io, &(monkeyenc->waveformatex), &(monkeyenc->total_blocks),
|
||||
&(monkeyenc->header_size), &(monkeyenc->terminating), &retval);
|
||||
|
||||
monkeyenc->audiobytes = monkeyenc->total_blocks * monkeyenc->waveformatex.nBlockAlign;
|
||||
monkeyenc->audiobytesleft = monkeyenc->audiobytes;
|
||||
|
||||
wav_header = (unsigned char*) g_malloc0 (monkeyenc->header_size);
|
||||
retval = monkeyenc->inputsrc->GetHeaderData (wav_header);
|
||||
|
||||
monkeyenc->compress_engine = CreateIAPECompress (&retval);
|
||||
|
||||
if (monkeyenc->compress_engine == NULL)
|
||||
{
|
||||
gst_element_error(GST_ELEMENT (monkeyenc), "Failed to initiliaze MonkeyAudio encoder engine : %d", retval);
|
||||
return;
|
||||
}
|
||||
|
||||
retval = monkeyenc->compress_engine->StartEx (monkeyenc->src_io, &(monkeyenc->waveformatex), monkeyenc->audiobytes,
|
||||
COMPRESSION_LEVEL_NORMAL, wav_header, monkeyenc->header_size);
|
||||
monkeyenc->init = FALSE;
|
||||
}
|
||||
|
||||
retval = monkeyenc->compress_engine->AddDataFromInputSource (monkeyenc->inputsrc, monkeyenc->audiobytesleft, &size);
|
||||
monkeyenc->audiobytesleft -= size;
|
||||
|
||||
if (monkeyenc->audiobytesleft <= 0)
|
||||
{
|
||||
unsigned char *terminating_data;
|
||||
|
||||
terminating_data = (unsigned char *) g_malloc0 (monkeyenc->terminating);
|
||||
retval = monkeyenc->inputsrc->GetTerminatingData (terminating_data);
|
||||
|
||||
retval = monkeyenc->compress_engine->Finish (terminating_data, monkeyenc->terminating, monkeyenc->terminating);
|
||||
|
||||
monkeyenc->sink_io->SetEOF();
|
||||
monkeyenc->src_io->SetEOF();
|
||||
monkeyenc->sink_io->Close();
|
||||
gst_element_set_eos (element);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static GstElementStateReturn
|
||||
gst_monkeyenc_change_state (GstElement *element)
|
||||
{
|
||||
GstMonkeyEnc *monkeyenc;
|
||||
|
||||
monkeyenc = GST_MONKEYENC (element);
|
||||
|
||||
switch (GST_STATE_TRANSITION (element)) {
|
||||
case GST_STATE_NULL_TO_READY:
|
||||
break;
|
||||
case GST_STATE_READY_TO_PAUSED:
|
||||
monkeyenc->init = TRUE;
|
||||
break;
|
||||
case GST_STATE_PAUSED_TO_PLAYING:
|
||||
/* do something to get out of the chain function faster */
|
||||
break;
|
||||
case GST_STATE_PLAYING_TO_PAUSED:
|
||||
break;
|
||||
case GST_STATE_PAUSED_TO_READY:
|
||||
break;
|
||||
case GST_STATE_READY_TO_NULL:
|
||||
break;
|
||||
}
|
||||
|
||||
parent_class->change_state (element);
|
||||
|
||||
return GST_STATE_SUCCESS;
|
||||
}
|
90
gst/monkeyaudio/gstmonkeyenc.h
Normal file
90
gst/monkeyaudio/gstmonkeyenc.h
Normal file
|
@ -0,0 +1,90 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library 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.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef __GST_MONKEYENC_H__
|
||||
#define __GST_MONKEYENC_H__
|
||||
|
||||
#include "libmonkeyaudio/All.h"
|
||||
#include "libmonkeyaudio/GlobalFunctions.h"
|
||||
#include "libmonkeyaudio/MACLib.h"
|
||||
#include "libmonkeyaudio/IO.h"
|
||||
#include "monkey_io.h"
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
#include "libmonkeyaudio/WAVInputSource.h"
|
||||
#include "libmonkeyaudio/NoWindows.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
|
||||
|
||||
#define GST_TYPE_MONKEYENC (gst_monkeyenc_get_type())
|
||||
#define GST_MONKEYENC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MONKEYENC,GstMonkeyEnc))
|
||||
#define GST_MONKEYENC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MONKEYENC,GstMonkeyEnc))
|
||||
#define GST_IS_MONKEYENC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MONKEYENC))
|
||||
#define GST_IS_MONKEYENC_CLASS(obj)(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MONKEYENC))
|
||||
|
||||
typedef struct _GstMonkeyEnc GstMonkeyEnc;
|
||||
typedef struct _GstMonkeyEncClass GstMonkeyEncClass;
|
||||
|
||||
extern GstPadTemplate *monkeyenc_src_template, *monkeyenc_sink_template;
|
||||
|
||||
struct _GstMonkeyEnc
|
||||
{
|
||||
GstElement element;
|
||||
|
||||
GstPad *sinkpad, *srcpad;
|
||||
gboolean init;
|
||||
gint channels;
|
||||
gint rate;
|
||||
gint depth;
|
||||
gboolean linked;
|
||||
gint total_blocks;
|
||||
gint header_size;
|
||||
gint terminating;
|
||||
guint64 audiobytes;
|
||||
guint64 audiobytesleft;
|
||||
|
||||
IAPECompress *compress_engine;
|
||||
WAVEFORMATEX waveformatex;
|
||||
WAVE_HEADER pWAVHeader;
|
||||
srcpad_CIO *src_io;
|
||||
sinkpad_CIO *sink_io;
|
||||
CWAVInputSource *inputsrc;
|
||||
|
||||
};
|
||||
|
||||
struct _GstMonkeyEncClass
|
||||
{
|
||||
GstElementClass parent_class;
|
||||
};
|
||||
|
||||
GType gst_monkeyenc_get_type(void);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __GST_MONKEYENC_H__ */
|
||||
|
245
gst/monkeyaudio/libmonkeyaudio/APECompress.cpp
Normal file
245
gst/monkeyaudio/libmonkeyaudio/APECompress.cpp
Normal file
|
@ -0,0 +1,245 @@
|
|||
#include "All.h"
|
||||
#include "APECompress.h"
|
||||
#include IO_HEADER_FILE
|
||||
#include "APECompressCreate.h"
|
||||
#include "WAVInputSource.h"
|
||||
|
||||
CAPECompress::CAPECompress()
|
||||
{
|
||||
m_nBufferHead = 0;
|
||||
m_nBufferTail = 0;
|
||||
m_nBufferSize = 0;
|
||||
m_bBufferLocked = FALSE;
|
||||
m_bOwnsOutputIO = FALSE;
|
||||
m_pioOutput = NULL;
|
||||
|
||||
m_spAPECompressCreate.Assign(new CAPECompressCreate());
|
||||
|
||||
m_pBuffer = NULL;
|
||||
}
|
||||
|
||||
CAPECompress::~CAPECompress()
|
||||
{
|
||||
SAFE_ARRAY_DELETE(m_pBuffer)
|
||||
|
||||
if (m_bOwnsOutputIO)
|
||||
{
|
||||
SAFE_DELETE(m_pioOutput)
|
||||
}
|
||||
}
|
||||
|
||||
int CAPECompress::Start(const char * pOutputFilename, const WAVEFORMATEX * pwfeInput, int nMaxAudioBytes, int nCompressionLevel, const unsigned char * pHeaderData, int nHeaderBytes)
|
||||
{
|
||||
m_pioOutput = new IO_CLASS_NAME;
|
||||
m_bOwnsOutputIO = TRUE;
|
||||
|
||||
if (m_pioOutput->Create(pOutputFilename) != 0)
|
||||
{
|
||||
return ERROR_INVALID_OUTPUT_FILE;
|
||||
}
|
||||
|
||||
m_spAPECompressCreate->Start(m_pioOutput, pwfeInput, nMaxAudioBytes, nCompressionLevel,
|
||||
pHeaderData, nHeaderBytes);
|
||||
|
||||
SAFE_ARRAY_DELETE(m_pBuffer)
|
||||
m_nBufferSize = m_spAPECompressCreate->GetFullFrameBytes();
|
||||
m_pBuffer = new unsigned char [m_nBufferSize];
|
||||
memcpy(&m_wfeInput, pwfeInput, sizeof(WAVEFORMATEX));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CAPECompress::StartEx(CIO * pioOutput, const WAVEFORMATEX * pwfeInput, int nMaxAudioBytes, int nCompressionLevel, const unsigned char * pHeaderData, int nHeaderBytes)
|
||||
{
|
||||
m_pioOutput = pioOutput;
|
||||
m_bOwnsOutputIO = FALSE;
|
||||
|
||||
m_spAPECompressCreate->Start(m_pioOutput, pwfeInput, nMaxAudioBytes, nCompressionLevel,
|
||||
pHeaderData, nHeaderBytes);
|
||||
|
||||
SAFE_ARRAY_DELETE(m_pBuffer)
|
||||
m_nBufferSize = m_spAPECompressCreate->GetFullFrameBytes();
|
||||
m_pBuffer = new unsigned char [m_nBufferSize];
|
||||
memcpy(&m_wfeInput, pwfeInput, sizeof(WAVEFORMATEX));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CAPECompress::GetBufferBytesAvailable()
|
||||
{
|
||||
return m_nBufferSize - m_nBufferTail;
|
||||
}
|
||||
|
||||
int CAPECompress::UnlockBuffer(int nBytesAdded, BOOL bProcess)
|
||||
{
|
||||
if (m_bBufferLocked == FALSE)
|
||||
return -1;
|
||||
|
||||
m_nBufferTail += nBytesAdded;
|
||||
m_bBufferLocked = FALSE;
|
||||
|
||||
if (bProcess)
|
||||
{
|
||||
int nRetVal = ProcessBuffer();
|
||||
if (nRetVal != 0) { return nRetVal; }
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned char * CAPECompress::LockBuffer(int * pBytesAvailable)
|
||||
{
|
||||
if (m_pBuffer == NULL) { return NULL; }
|
||||
|
||||
if (m_bBufferLocked)
|
||||
return NULL;
|
||||
|
||||
m_bBufferLocked = TRUE;
|
||||
|
||||
if (pBytesAvailable)
|
||||
*pBytesAvailable = GetBufferBytesAvailable();
|
||||
|
||||
return &m_pBuffer[m_nBufferTail];
|
||||
}
|
||||
|
||||
int CAPECompress::AddData(unsigned char * pData, int nBytes)
|
||||
{
|
||||
if (m_pBuffer == NULL) return ERROR_INSUFFICIENT_MEMORY;
|
||||
|
||||
int nBytesDone = 0;
|
||||
|
||||
while (nBytesDone < nBytes)
|
||||
{
|
||||
// lock the buffer
|
||||
int nBytesAvailable = 0;
|
||||
unsigned char * pBuffer = LockBuffer(&nBytesAvailable);
|
||||
if (pBuffer == NULL || nBytesAvailable <= 0)
|
||||
return -1;
|
||||
|
||||
// calculate how many bytes to copy and add that much to the buffer
|
||||
int nBytesToProcess = min(nBytesAvailable, nBytes - nBytesDone);
|
||||
memcpy(pBuffer, &pData[nBytesDone], nBytesToProcess);
|
||||
|
||||
// unlock the buffer (fail if not successful)
|
||||
int nRetVal = UnlockBuffer(nBytesToProcess);
|
||||
if (nRetVal != ERROR_SUCCESS)
|
||||
return nRetVal;
|
||||
|
||||
// update our progress
|
||||
nBytesDone += nBytesToProcess;
|
||||
}
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
int CAPECompress::Finish(unsigned char * pTerminatingData, int nTerminatingBytes, int nWAVTerminatingBytes)
|
||||
{
|
||||
RETURN_ON_ERROR(ProcessBuffer(TRUE))
|
||||
return m_spAPECompressCreate->Finish(pTerminatingData, nTerminatingBytes, nWAVTerminatingBytes);
|
||||
}
|
||||
|
||||
int CAPECompress::Kill()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CAPECompress::ProcessBuffer(BOOL bFinalize)
|
||||
{
|
||||
if (m_pBuffer == NULL) { return -1; }
|
||||
|
||||
try
|
||||
{
|
||||
// process as much as possible
|
||||
int nThreshold = (bFinalize) ? 0 : m_spAPECompressCreate->GetFullFrameBytes();
|
||||
|
||||
while ((m_nBufferTail - m_nBufferHead) >= nThreshold)
|
||||
{
|
||||
int nFrameBytes = min(m_spAPECompressCreate->GetFullFrameBytes(), m_nBufferTail - m_nBufferHead);
|
||||
|
||||
if (nFrameBytes == 0)
|
||||
break;
|
||||
|
||||
int nRetVal = m_spAPECompressCreate->EncodeFrame(&m_pBuffer[m_nBufferHead], nFrameBytes);
|
||||
if (nRetVal != 0) { return nRetVal; }
|
||||
|
||||
m_nBufferHead += nFrameBytes;
|
||||
}
|
||||
|
||||
// shift the buffer
|
||||
if (m_nBufferHead != 0)
|
||||
{
|
||||
int nBytesLeft = m_nBufferTail - m_nBufferHead;
|
||||
|
||||
if (nBytesLeft != 0)
|
||||
memmove(m_pBuffer, &m_pBuffer[m_nBufferHead], nBytesLeft);
|
||||
|
||||
m_nBufferTail -= m_nBufferHead;
|
||||
m_nBufferHead = 0;
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CAPECompress::AddDataFromInputSource(CInputSource * pInputSource, int nMaxBytes, int * pBytesAdded)
|
||||
{
|
||||
// error check the parameters
|
||||
if (pInputSource == NULL) return ERROR_BAD_PARAMETER;
|
||||
|
||||
// initialize
|
||||
if (pBytesAdded) *pBytesAdded = 0;
|
||||
|
||||
// lock the buffer
|
||||
int nBytesAvailable = 0;
|
||||
unsigned char * pBuffer = LockBuffer(&nBytesAvailable);
|
||||
if ((pBuffer == NULL) || (nBytesAvailable == 0))
|
||||
return ERROR_INSUFFICIENT_MEMORY;
|
||||
|
||||
// calculate the 'ideal' number of bytes
|
||||
unsigned int nBytesRead = 0;
|
||||
|
||||
int nIdealBytes = m_spAPECompressCreate->GetFullFrameBytes() - (m_nBufferTail - m_nBufferHead);
|
||||
if (nIdealBytes > 0)
|
||||
{
|
||||
// get the data
|
||||
int nBytesToAdd = nBytesAvailable;
|
||||
|
||||
if (nMaxBytes > 0)
|
||||
{
|
||||
if (nBytesToAdd > nMaxBytes) nBytesToAdd = nMaxBytes;
|
||||
}
|
||||
|
||||
if (nBytesToAdd > nIdealBytes) nBytesToAdd = nIdealBytes;
|
||||
|
||||
// always make requests along block boundaries
|
||||
while ((nBytesToAdd % m_wfeInput.nBlockAlign) != 0)
|
||||
nBytesToAdd--;
|
||||
|
||||
int nBlocksToAdd = nBytesToAdd / m_wfeInput.nBlockAlign;
|
||||
|
||||
// get data
|
||||
int nBlocksAdded = 0;
|
||||
int nRetVal = pInputSource->GetData(pBuffer, nBlocksToAdd, &nBlocksAdded);
|
||||
if (nRetVal != 0)
|
||||
return ERROR_IO_READ;
|
||||
else
|
||||
nBytesRead = (nBlocksAdded * m_wfeInput.nBlockAlign);
|
||||
|
||||
// store the bytes read
|
||||
if (pBytesAdded)
|
||||
*pBytesAdded = nBytesRead;
|
||||
}
|
||||
|
||||
// unlock the data and process
|
||||
int nRetVal = UnlockBuffer(nBytesRead, TRUE);
|
||||
if (nRetVal != 0)
|
||||
{
|
||||
return nRetVal;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
55
gst/monkeyaudio/libmonkeyaudio/APECompress.h
Normal file
55
gst/monkeyaudio/libmonkeyaudio/APECompress.h
Normal file
|
@ -0,0 +1,55 @@
|
|||
#ifndef MAC_APECOMPRESS_H
|
||||
#define MAC_APECOMPRESS_H
|
||||
|
||||
#include "MACLib.h"
|
||||
class CAPECompressCreate;
|
||||
|
||||
/*************************************************************************************************
|
||||
CAPECompress - uses the CAPECompressHub to provide a simpler compression interface (with buffering, etc)
|
||||
*************************************************************************************************/
|
||||
class CAPECompress : public IAPECompress
|
||||
{
|
||||
public:
|
||||
CAPECompress();
|
||||
~CAPECompress();
|
||||
|
||||
// start encoding
|
||||
int Start(const char * pOutputFilename, const WAVEFORMATEX * pwfeInput, int nMaxAudioBytes, int nCompressionLevel = COMPRESSION_LEVEL_NORMAL, const unsigned char * pHeaderData = NULL, int nHeaderBytes = CREATE_WAV_HEADER_ON_DECOMPRESSION);
|
||||
int StartEx(CIO * pioOutput, const WAVEFORMATEX * pwfeInput, int nMaxAudioBytes, int nCompressionLevel = COMPRESSION_LEVEL_NORMAL, const unsigned char * pHeaderData = NULL, int nHeaderBytes = CREATE_WAV_HEADER_ON_DECOMPRESSION);
|
||||
|
||||
// add data / compress data
|
||||
|
||||
// allows linear, immediate access to the buffer (fast)
|
||||
int GetBufferBytesAvailable();
|
||||
int UnlockBuffer(int nBytesAdded, BOOL bProcess = TRUE);
|
||||
unsigned char * LockBuffer(int * pBytesAvailable);
|
||||
|
||||
// slower, but easier than locking and unlocking (copies data)
|
||||
int AddData(unsigned char * pData, int nBytes);
|
||||
|
||||
// use a CIO (input source) to add data
|
||||
int AddDataFromInputSource(CInputSource * pInputSource, int nMaxBytes = -1, int * pBytesAdded = NULL);
|
||||
|
||||
// finish / kill
|
||||
int Finish(unsigned char * pTerminatingData, int nTerminatingBytes, int nWAVTerminatingBytes);
|
||||
int Kill();
|
||||
|
||||
private:
|
||||
|
||||
int ProcessBuffer(BOOL bFinalize = FALSE);
|
||||
|
||||
CSmartPtr<CAPECompressCreate> m_spAPECompressCreate;
|
||||
|
||||
int m_nBufferHead;
|
||||
int m_nBufferTail;
|
||||
int m_nBufferSize;
|
||||
unsigned char * m_pBuffer;
|
||||
BOOL m_bBufferLocked;
|
||||
|
||||
CIO * m_pioOutput;
|
||||
BOOL m_bOwnsOutputIO;
|
||||
WAVEFORMATEX m_wfeInput;
|
||||
|
||||
};
|
||||
|
||||
#endif /* MAC_APECOMPRESS_H */
|
126
gst/monkeyaudio/libmonkeyaudio/APECompressCore.cpp
Normal file
126
gst/monkeyaudio/libmonkeyaudio/APECompressCore.cpp
Normal file
|
@ -0,0 +1,126 @@
|
|||
#include "All.h"
|
||||
#include "APECompressCore.h"
|
||||
|
||||
#include "BitArray.h"
|
||||
#include "Prepare.h"
|
||||
#include "NewPredictor.h"
|
||||
|
||||
CAPECompressCore::CAPECompressCore(CIO * pIO, const WAVEFORMATEX * pwfeInput, int nMaxFrameBlocks, int nCompressionLevel)
|
||||
{
|
||||
m_spBitArray.Assign(new CBitArray(pIO));
|
||||
m_spDataX.Assign(new int [nMaxFrameBlocks], TRUE);
|
||||
m_spDataY.Assign(new int [nMaxFrameBlocks], TRUE);
|
||||
m_spTempData.Assign(new int [nMaxFrameBlocks], TRUE);
|
||||
m_spPrepare.Assign(new CPrepare);
|
||||
m_spPredictorX.Assign(new CPredictorCompressNormal(nCompressionLevel));
|
||||
m_spPredictorY.Assign(new CPredictorCompressNormal(nCompressionLevel));
|
||||
|
||||
memcpy(&m_wfeInput, pwfeInput, sizeof(WAVEFORMATEX));
|
||||
m_nPeakLevel = 0;
|
||||
}
|
||||
|
||||
CAPECompressCore::~CAPECompressCore()
|
||||
{
|
||||
}
|
||||
|
||||
int CAPECompressCore::EncodeFrame(unsigned char * pInputData, int nInputBytes)
|
||||
{
|
||||
// variables
|
||||
const int nInputBlocks = nInputBytes / m_wfeInput.nBlockAlign;
|
||||
int nSpecialCodes = 0;
|
||||
|
||||
// always start a new frame on a byte boundary
|
||||
m_spBitArray->AdvanceToByteBoundary();
|
||||
|
||||
// do the preparation stage
|
||||
RETURN_ON_ERROR(Prepare(pInputData, nInputBytes, &nSpecialCodes))
|
||||
|
||||
m_spPredictorX->Flush();
|
||||
m_spPredictorY->Flush();
|
||||
|
||||
m_spBitArray->FlushState(m_BitArrayStateX);
|
||||
m_spBitArray->FlushState(m_BitArrayStateY);
|
||||
|
||||
m_spBitArray->FlushBitArray();
|
||||
|
||||
if (m_wfeInput.nChannels == 2)
|
||||
{
|
||||
BOOL bEncodeX = TRUE;
|
||||
BOOL bEncodeY = TRUE;
|
||||
|
||||
if ((nSpecialCodes & SPECIAL_FRAME_LEFT_SILENCE) &&
|
||||
(nSpecialCodes & SPECIAL_FRAME_RIGHT_SILENCE))
|
||||
{
|
||||
bEncodeX = FALSE;
|
||||
bEncodeY = FALSE;
|
||||
}
|
||||
|
||||
if (nSpecialCodes & SPECIAL_FRAME_PSEUDO_STEREO)
|
||||
{
|
||||
bEncodeY = FALSE;
|
||||
}
|
||||
|
||||
if (bEncodeX && bEncodeY)
|
||||
{
|
||||
int nLastX = 0;
|
||||
for (int z = 0; z < nInputBlocks; z++)
|
||||
{
|
||||
m_spBitArray->EncodeValue(m_spPredictorY->CompressValue(m_spDataY[z], nLastX), m_BitArrayStateY);
|
||||
m_spBitArray->EncodeValue(m_spPredictorX->CompressValue(m_spDataX[z], m_spDataY[z]), m_BitArrayStateX);
|
||||
|
||||
nLastX = m_spDataX[z];
|
||||
}
|
||||
}
|
||||
else if (bEncodeX)
|
||||
{
|
||||
for (int z = 0; z < nInputBlocks; z++)
|
||||
{
|
||||
RETURN_ON_ERROR(m_spBitArray->EncodeValue(m_spPredictorX->CompressValue(m_spDataX[z]), m_BitArrayStateX))
|
||||
}
|
||||
}
|
||||
else if (bEncodeY)
|
||||
{
|
||||
for (int z = 0; z < nInputBlocks; z++)
|
||||
{
|
||||
RETURN_ON_ERROR(m_spBitArray->EncodeValue(m_spPredictorY->CompressValue(m_spDataY[z]), m_BitArrayStateY))
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (m_wfeInput.nChannels == 1)
|
||||
{
|
||||
if (!(nSpecialCodes & SPECIAL_FRAME_MONO_SILENCE))
|
||||
{
|
||||
for (int z = 0; z < nInputBlocks; z++)
|
||||
{
|
||||
RETURN_ON_ERROR(m_spBitArray->EncodeValue(m_spPredictorX->CompressValue(m_spDataX[z]), m_BitArrayStateX))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_spBitArray->Finalize();
|
||||
|
||||
// return success
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CAPECompressCore::Prepare(unsigned char * pInputData, int nInputBytes, int * pSpecialCodes)
|
||||
{
|
||||
// variable declares
|
||||
*pSpecialCodes = 0;
|
||||
unsigned int nCRC = 0;
|
||||
|
||||
// do the preparation
|
||||
RETURN_ON_ERROR(m_spPrepare->Prepare(pInputData, nInputBytes, &m_wfeInput, m_spDataX, m_spDataY,
|
||||
&nCRC, pSpecialCodes, &m_nPeakLevel))
|
||||
|
||||
// store the CRC
|
||||
RETURN_ON_ERROR(m_spBitArray->EncodeUnsignedLong(nCRC))
|
||||
|
||||
// store any special codes
|
||||
if (*pSpecialCodes != 0)
|
||||
{
|
||||
RETURN_ON_ERROR(m_spBitArray->EncodeUnsignedLong(*pSpecialCodes))
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
46
gst/monkeyaudio/libmonkeyaudio/APECompressCore.h
Normal file
46
gst/monkeyaudio/libmonkeyaudio/APECompressCore.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
#ifndef APE_APECOMPRESSCORE_H
|
||||
#define APE_APECOMPRESSCORE_H
|
||||
|
||||
#include "APECompress.h"
|
||||
#include "BitArray.h"
|
||||
|
||||
class CPrepare;
|
||||
class IPredictorCompress;
|
||||
|
||||
/*************************************************************************************************
|
||||
CAPECompressCore - manages the core of compression and bitstream output
|
||||
*************************************************************************************************/
|
||||
class CAPECompressCore
|
||||
{
|
||||
public:
|
||||
CAPECompressCore(CIO * pIO, const WAVEFORMATEX * pwfeInput, int nMaxFrameBlocks, int nCompressionLevel);
|
||||
~CAPECompressCore();
|
||||
|
||||
int EncodeFrame(unsigned char * pInputData, int nInputBytes);
|
||||
|
||||
CBitArray * GetBitArray() { return m_spBitArray.GetPtr(); }
|
||||
int GetPeakLevel() { return m_nPeakLevel; }
|
||||
|
||||
private:
|
||||
|
||||
CSmartPtr<CBitArray> m_spBitArray;
|
||||
CSmartPtr<IPredictorCompress> m_spPredictorX;
|
||||
CSmartPtr<IPredictorCompress> m_spPredictorY;
|
||||
|
||||
BIT_ARRAY_STATE m_BitArrayStateX;
|
||||
BIT_ARRAY_STATE m_BitArrayStateY;
|
||||
|
||||
CSmartPtr<int> m_spDataX;
|
||||
CSmartPtr<int> m_spDataY;
|
||||
CSmartPtr<int> m_spTempData;
|
||||
|
||||
CSmartPtr<CPrepare> m_spPrepare;
|
||||
|
||||
WAVEFORMATEX m_wfeInput;
|
||||
|
||||
int m_nPeakLevel;
|
||||
|
||||
int Prepare(unsigned char * pInputData, int nInputBytes, int * pSpecialCodes);
|
||||
};
|
||||
|
||||
#endif /* APE_APECOMPRESSCORE_H */
|
203
gst/monkeyaudio/libmonkeyaudio/APECompressCreate.cpp
Normal file
203
gst/monkeyaudio/libmonkeyaudio/APECompressCreate.cpp
Normal file
|
@ -0,0 +1,203 @@
|
|||
#include "All.h"
|
||||
#include "IO.h"
|
||||
#include "APECompressCreate.h"
|
||||
|
||||
#include "APECompressCore.h"
|
||||
|
||||
CAPECompressCreate::CAPECompressCreate()
|
||||
{
|
||||
m_nMaxFrames = 0;
|
||||
}
|
||||
|
||||
CAPECompressCreate::~CAPECompressCreate()
|
||||
{
|
||||
}
|
||||
|
||||
int CAPECompressCreate::Start(CIO * pioOutput, const WAVEFORMATEX * pwfeInput, int nMaxAudioBytes, int nCompressionLevel, const unsigned char * pHeaderData, int nHeaderBytes)
|
||||
{
|
||||
// verify the parameters
|
||||
if (pioOutput == NULL || pwfeInput == NULL)
|
||||
return ERROR_BAD_PARAMETER;
|
||||
|
||||
// verify the wave format
|
||||
if ((pwfeInput->nChannels != 1) && (pwfeInput->nChannels != 2))
|
||||
{
|
||||
return ERROR_INPUT_FILE_UNSUPPORTED_CHANNEL_COUNT;
|
||||
}
|
||||
if ((pwfeInput->wBitsPerSample != 8) && (pwfeInput->wBitsPerSample != 16) && (pwfeInput->wBitsPerSample != 24))
|
||||
{
|
||||
return ERROR_INPUT_FILE_UNSUPPORTED_BIT_DEPTH;
|
||||
}
|
||||
|
||||
// initialize (creates the base classes)
|
||||
m_nSamplesPerFrame = 73728 * 4;
|
||||
|
||||
m_spIO.Assign(pioOutput, FALSE, FALSE);
|
||||
m_spAPECompressCore.Assign(new CAPECompressCore(m_spIO, pwfeInput, m_nSamplesPerFrame, nCompressionLevel));
|
||||
|
||||
// copy the format
|
||||
memcpy(&m_wfeInput, pwfeInput, sizeof(WAVEFORMATEX));
|
||||
|
||||
// the compression level
|
||||
m_nCompressionLevel = nCompressionLevel;
|
||||
m_nFrameIndex = 0;
|
||||
m_nLastFrameBlocks = m_nSamplesPerFrame;
|
||||
|
||||
// initialize the file
|
||||
if (nMaxAudioBytes < 0)
|
||||
nMaxAudioBytes = 2147483647;
|
||||
|
||||
unsigned __int32 nMaxAudioBlocks = nMaxAudioBytes / pwfeInput->nBlockAlign;
|
||||
int nMaxFrames = nMaxAudioBlocks / m_nSamplesPerFrame;
|
||||
if ((nMaxAudioBlocks % m_nSamplesPerFrame) != 0) nMaxFrames++;
|
||||
|
||||
InitializeFile(m_spIO, &m_wfeInput, nMaxFrames,
|
||||
m_nCompressionLevel, pHeaderData, nHeaderBytes);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CAPECompressCreate::GetFullFrameBytes()
|
||||
{
|
||||
return m_nSamplesPerFrame * m_wfeInput.nBlockAlign;
|
||||
}
|
||||
|
||||
int CAPECompressCreate::EncodeFrame(unsigned char * pInputData, int nInputBytes)
|
||||
{
|
||||
int nInputBlocks = nInputBytes / m_wfeInput.nBlockAlign;
|
||||
|
||||
if ((nInputBlocks < m_nSamplesPerFrame) && (m_nLastFrameBlocks < m_nSamplesPerFrame))
|
||||
{
|
||||
return -1; //can only pass a smaller frame for the very last time
|
||||
}
|
||||
|
||||
// update the seek table
|
||||
m_spAPECompressCore->GetBitArray()->AdvanceToByteBoundary();
|
||||
int nRetVal = SetSeekByte(m_nFrameIndex, m_spIO->GetPosition() + (m_spAPECompressCore->GetBitArray()->GetCurrentBitIndex() / 8));
|
||||
if (nRetVal != ERROR_SUCCESS)
|
||||
return nRetVal;
|
||||
|
||||
// compress
|
||||
nRetVal = m_spAPECompressCore->EncodeFrame(pInputData, nInputBytes);
|
||||
|
||||
// update stats
|
||||
m_nLastFrameBlocks = nInputBlocks;
|
||||
m_nFrameIndex++;
|
||||
|
||||
return nRetVal;
|
||||
}
|
||||
|
||||
int CAPECompressCreate::Finish(unsigned char * pTerminatingData, int nTerminatingBytes, int nWAVTerminatingBytes)
|
||||
{
|
||||
// clear the bit array
|
||||
RETURN_ON_ERROR(m_spAPECompressCore->GetBitArray()->OutputBitArray(TRUE));
|
||||
|
||||
// finalize the file
|
||||
RETURN_ON_ERROR(FinalizeFile(m_spIO, m_nFrameIndex, m_nLastFrameBlocks,
|
||||
pTerminatingData, nTerminatingBytes, nWAVTerminatingBytes, m_spAPECompressCore->GetPeakLevel()));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CAPECompressCreate::SetSeekByte(int nFrame, int nByteOffset)
|
||||
{
|
||||
if (nFrame >= m_nMaxFrames) return ERROR_APE_COMPRESS_TOO_MUCH_DATA;
|
||||
m_spSeekTable[nFrame] = nByteOffset;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CAPECompressCreate::InitializeFile(CIO * pIO, const WAVEFORMATEX * pwfeInput, int nMaxFrames, int nCompressionLevel, const unsigned char * pHeaderData, int nHeaderBytes)
|
||||
{
|
||||
// error check the parameters
|
||||
if (pIO == NULL || pwfeInput == NULL || nMaxFrames <= 0)
|
||||
return ERROR_BAD_PARAMETER;
|
||||
|
||||
// create a MAC header using the audio format info
|
||||
APE_HEADER APEHeader;
|
||||
APEHeader.cID[0] = 'M';
|
||||
APEHeader.cID[1] = 'A';
|
||||
APEHeader.cID[2] = 'C';
|
||||
APEHeader.cID[3] = ' ';
|
||||
APEHeader.nVersion = MAC_VERSION_NUMBER;
|
||||
APEHeader.nChannels = pwfeInput->nChannels;
|
||||
APEHeader.nCompressionLevel = (unsigned __int16) nCompressionLevel;
|
||||
APEHeader.nSampleRate = pwfeInput->nSamplesPerSec;
|
||||
APEHeader.nHeaderBytes = (nHeaderBytes == CREATE_WAV_HEADER_ON_DECOMPRESSION) ? 0 : nHeaderBytes;
|
||||
APEHeader.nTerminatingBytes = 0;
|
||||
|
||||
// the format flag(s)
|
||||
APEHeader.nFormatFlags = MAC_FORMAT_FLAG_CRC | MAC_FORMAT_FLAG_HAS_PEAK_LEVEL | MAC_FORMAT_FLAG_HAS_SEEK_ELEMENTS;
|
||||
|
||||
if (nHeaderBytes == CREATE_WAV_HEADER_ON_DECOMPRESSION)
|
||||
APEHeader.nFormatFlags |= MAC_FORMAT_FLAG_CREATE_WAV_HEADER;
|
||||
|
||||
if (pwfeInput->wBitsPerSample == 8)
|
||||
APEHeader.nFormatFlags |= MAC_FORMAT_FLAG_8_BIT;
|
||||
else if (pwfeInput->wBitsPerSample == 24)
|
||||
APEHeader.nFormatFlags |= MAC_FORMAT_FLAG_24_BIT;
|
||||
|
||||
// the number of frames
|
||||
APEHeader.nTotalFrames = 0;
|
||||
APEHeader.nFinalFrameBlocks = 0;
|
||||
|
||||
// write the data to the file
|
||||
unsigned int BytesWritten = 0;
|
||||
RETURN_ON_ERROR(pIO->Write(&APEHeader, APE_HEADER_BYTES, &BytesWritten))
|
||||
|
||||
int nPeakLevel = -1;
|
||||
RETURN_ON_ERROR(pIO->Write(&nPeakLevel, 4, &BytesWritten))
|
||||
|
||||
RETURN_ON_ERROR(pIO->Write(&nMaxFrames, 4, &BytesWritten))
|
||||
|
||||
if ((pHeaderData != NULL) && (nHeaderBytes > 0) && (nHeaderBytes != CREATE_WAV_HEADER_ON_DECOMPRESSION))
|
||||
RETURN_ON_ERROR(pIO->Write((void *) pHeaderData, nHeaderBytes, &BytesWritten))
|
||||
|
||||
// write an empty seek table
|
||||
m_spSeekTable.Assign(new unsigned __int32 [nMaxFrames], TRUE);
|
||||
if (m_spSeekTable == NULL) { return ERROR_INSUFFICIENT_MEMORY; }
|
||||
ZeroMemory(m_spSeekTable, nMaxFrames * 4);
|
||||
RETURN_ON_ERROR(pIO->Write(m_spSeekTable, (nMaxFrames * 4), &BytesWritten))
|
||||
m_nMaxFrames = nMaxFrames;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int CAPECompressCreate::FinalizeFile(CIO * pIO, int nNumberOfFrames, int nFinalFrameBlocks, const unsigned char * pTerminatingData, int nTerminatingBytes, int nWAVTerminatingBytes, int nPeakLevel)
|
||||
{
|
||||
// append the terminating data
|
||||
unsigned int BytesWritten = 0;
|
||||
unsigned int BytesRead = 0;
|
||||
int nRetVal = 0;
|
||||
|
||||
if (nTerminatingBytes > 0)
|
||||
{
|
||||
if (pIO->Write((void *) pTerminatingData, nTerminatingBytes, &BytesWritten) != 0) { return ERROR_IO_WRITE; }
|
||||
}
|
||||
|
||||
// go to the beginning and update the information
|
||||
nRetVal = pIO->Seek(0, FILE_BEGIN);
|
||||
|
||||
// get the current header
|
||||
APE_HEADER APEHeader;
|
||||
nRetVal = pIO->Read(&APEHeader, APE_HEADER_BYTES, &BytesRead);
|
||||
if (nRetVal != 0 || BytesRead != APE_HEADER_BYTES) { return ERROR_IO_READ; }
|
||||
|
||||
// update the header
|
||||
APEHeader.nTerminatingBytes = nWAVTerminatingBytes;
|
||||
APEHeader.nFinalFrameBlocks = nFinalFrameBlocks;
|
||||
APEHeader.nTotalFrames = nNumberOfFrames;
|
||||
|
||||
// set the pointer and re-write the updated header and peak level
|
||||
nRetVal = pIO->Seek(0, FILE_BEGIN);
|
||||
if (pIO->Write(&APEHeader, APE_HEADER_BYTES, &BytesWritten) != 0) { return ERROR_IO_WRITE; }
|
||||
if (pIO->Write(&nPeakLevel, 4, &BytesWritten) != 0) { return ERROR_IO_WRITE; }
|
||||
if (pIO->Write(&m_nMaxFrames, 4, &BytesWritten) != 0) { return ERROR_IO_WRITE; }
|
||||
|
||||
// write the updated seek table
|
||||
nRetVal = pIO->Seek(APEHeader.nHeaderBytes, FILE_CURRENT);
|
||||
|
||||
if (pIO->Write(m_spSeekTable, m_nMaxFrames * 4, &BytesWritten) != 0) { return ERROR_IO_WRITE; }
|
||||
|
||||
return 0;
|
||||
}
|
43
gst/monkeyaudio/libmonkeyaudio/APECompressCreate.h
Normal file
43
gst/monkeyaudio/libmonkeyaudio/APECompressCreate.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
#ifndef APE_COMPRESSCREATE_H
|
||||
#define APE_COMPRESSCREATE_H
|
||||
|
||||
#include "APECompress.h"
|
||||
|
||||
class CAPECompressCore;
|
||||
|
||||
class CAPECompressCreate
|
||||
{
|
||||
public:
|
||||
CAPECompressCreate();
|
||||
~CAPECompressCreate();
|
||||
|
||||
int InitializeFile(CIO * pIO, const WAVEFORMATEX * pwfeInput, int nMaxFrames, int nCompressionLevel, const unsigned char * pHeaderData, int nHeaderBytes);
|
||||
int FinalizeFile(CIO * pIO, int nNumberOfFrames, int nFinalFrameBlocks, const unsigned char * pTerminatingData, int nTerminatingBytes, int nWAVTerminatingBytes, int nPeakLevel);
|
||||
|
||||
int SetSeekByte(int nFrame, int nByteOffset);
|
||||
|
||||
int Start(CIO * pioOutput, const WAVEFORMATEX * pwfeInput, int nMaxAudioBytes, int nCompressionLevel = COMPRESSION_LEVEL_NORMAL, const unsigned char * pHeaderData = NULL, int nHeaderBytes = CREATE_WAV_HEADER_ON_DECOMPRESSION);
|
||||
|
||||
int GetFullFrameBytes();
|
||||
int EncodeFrame(unsigned char * pInputData, int nInputBytes);
|
||||
|
||||
int Finish(unsigned char * pTerminatingData, int nTerminatingBytes, int nWAVTerminatingBytes);
|
||||
|
||||
|
||||
private:
|
||||
|
||||
CSmartPtr<unsigned __int32> m_spSeekTable;
|
||||
int m_nMaxFrames;
|
||||
|
||||
CSmartPtr<CIO> m_spIO;
|
||||
CSmartPtr<CAPECompressCore> m_spAPECompressCore;
|
||||
|
||||
WAVEFORMATEX m_wfeInput;
|
||||
int m_nCompressionLevel;
|
||||
int m_nSamplesPerFrame;
|
||||
int m_nFrameIndex;
|
||||
int m_nLastFrameBlocks;
|
||||
|
||||
};
|
||||
|
||||
#endif /* APE_COMPRESSCREATE_H */
|
447
gst/monkeyaudio/libmonkeyaudio/APEDecompress.cpp
Normal file
447
gst/monkeyaudio/libmonkeyaudio/APEDecompress.cpp
Normal file
|
@ -0,0 +1,447 @@
|
|||
#include "All.h"
|
||||
#include "APEDecompress.h"
|
||||
|
||||
#include "APEInfo.h"
|
||||
#include "Prepare.h"
|
||||
#include "UnBitArray.h"
|
||||
#include "NewPredictor.h"
|
||||
|
||||
CAPEDecompress::CAPEDecompress(int * pErrorCode, CAPEInfo * pAPEInfo, int nStartBlock, int nFinishBlock)
|
||||
{
|
||||
*pErrorCode = ERROR_SUCCESS;
|
||||
|
||||
// open / analyze the file
|
||||
m_spAPEInfo.Assign(pAPEInfo);
|
||||
|
||||
// version check (this implementation only works with 3.93 and later files)
|
||||
if (GetInfo(APE_INFO_FILE_VERSION) < 3930)
|
||||
{
|
||||
*pErrorCode = ERROR_UNDEFINED;
|
||||
return;
|
||||
}
|
||||
|
||||
// get format information
|
||||
GetInfo(APE_INFO_WAVEFORMATEX, (int) &m_wfeInput);
|
||||
m_nBlockAlign = GetInfo(APE_INFO_BLOCK_ALIGN);
|
||||
|
||||
// initialize other stuff
|
||||
m_bDecompressorInitialized = FALSE;
|
||||
m_nCurrentFrame = 0;
|
||||
m_nCurrentBlock = 0;
|
||||
|
||||
// set the "real" start and finish blocks
|
||||
m_nStartBlock = (nStartBlock < 0) ? 0 : min(nStartBlock, GetInfo(APE_INFO_TOTAL_BLOCKS));
|
||||
m_nFinishBlock = (nFinishBlock < 0) ? GetInfo(APE_INFO_TOTAL_BLOCKS) : min(nFinishBlock, GetInfo(APE_INFO_TOTAL_BLOCKS));
|
||||
m_bIsRanged = (m_nStartBlock != 0) || (m_nFinishBlock != GetInfo(APE_INFO_TOTAL_BLOCKS));
|
||||
}
|
||||
|
||||
CAPEDecompress::~CAPEDecompress()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
int CAPEDecompress::InitializeDecompressor()
|
||||
{
|
||||
// check if we have anything to do
|
||||
if (m_bDecompressorInitialized)
|
||||
return ERROR_SUCCESS;
|
||||
|
||||
// update the initialized flag
|
||||
m_bDecompressorInitialized = TRUE;
|
||||
|
||||
// create decoding components
|
||||
m_spUnBitArray.Assign((CUnBitArrayBase *) CreateUnBitArray(this, GetInfo(APE_INFO_FILE_VERSION)));
|
||||
if (GetInfo(APE_INFO_FILE_VERSION) >= 3950)
|
||||
{
|
||||
m_spNewPredictorX.Assign(new CPredictorDecompress3950toCurrent(GetInfo(APE_INFO_COMPRESSION_LEVEL)));
|
||||
m_spNewPredictorY.Assign(new CPredictorDecompress3950toCurrent(GetInfo(APE_INFO_COMPRESSION_LEVEL)));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_spNewPredictorX.Assign(new CPredictorDecompressNormal3930to3950(GetInfo(APE_INFO_COMPRESSION_LEVEL)));
|
||||
m_spNewPredictorY.Assign(new CPredictorDecompressNormal3930to3950(GetInfo(APE_INFO_COMPRESSION_LEVEL)));
|
||||
}
|
||||
|
||||
// seek to the beginning
|
||||
return Seek(0);
|
||||
}
|
||||
|
||||
int CAPEDecompress::GetData(char * pBuffer, int nBlocks, int * pBlocksRetrieved)
|
||||
{
|
||||
|
||||
if (pBlocksRetrieved) *pBlocksRetrieved = 0;
|
||||
|
||||
RETURN_ON_ERROR(InitializeDecompressor())
|
||||
|
||||
// cap
|
||||
int nBlocksUntilFinish = m_nFinishBlock - m_nCurrentBlock;
|
||||
const int nBlocksToRetrieve = min(nBlocks, nBlocksUntilFinish);
|
||||
|
||||
int nRetVal = GetBlocks((unsigned char *) pBuffer, nBlocksToRetrieve);
|
||||
|
||||
m_nCurrentBlock += nBlocksToRetrieve;
|
||||
|
||||
if (pBlocksRetrieved) *pBlocksRetrieved = nBlocksToRetrieve;
|
||||
|
||||
return nRetVal;
|
||||
}
|
||||
|
||||
int CAPEDecompress::Seek(int nBlockOffset)
|
||||
{
|
||||
RETURN_ON_ERROR(InitializeDecompressor())
|
||||
|
||||
// use the offset
|
||||
nBlockOffset += m_nStartBlock;
|
||||
|
||||
// cap (to prevent seeking too far)
|
||||
if (nBlockOffset >= m_nFinishBlock)
|
||||
nBlockOffset = m_nFinishBlock - 1;
|
||||
if (nBlockOffset < m_nStartBlock)
|
||||
nBlockOffset = m_nStartBlock;
|
||||
|
||||
// seek to the perfect location
|
||||
int nBaseFrame = nBlockOffset / GetInfo(APE_INFO_BLOCKS_PER_FRAME);
|
||||
int nBlocksToSkip = nBlockOffset % GetInfo(APE_INFO_BLOCKS_PER_FRAME);
|
||||
int nBytesToSkip = nBlocksToSkip * m_nBlockAlign;
|
||||
|
||||
m_nCurrentFrame = nBaseFrame;
|
||||
RETURN_ON_ERROR(SeekToFrame(m_nCurrentFrame));
|
||||
|
||||
m_nBlocksProcessed = 0;
|
||||
|
||||
// skip necessary blocks
|
||||
CSmartPtr<char> spTempBuffer(new char [nBytesToSkip], TRUE);
|
||||
if (spTempBuffer == NULL) return ERROR_INSUFFICIENT_MEMORY;
|
||||
|
||||
int nBlocksRetrieved = 0;
|
||||
GetData(spTempBuffer, nBlocksToSkip, &nBlocksRetrieved);
|
||||
if (nBlocksRetrieved != nBlocksToSkip)
|
||||
return ERROR_UNDEFINED;
|
||||
|
||||
m_nCurrentBlock = nBlockOffset;
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
/*****************************************************************************************
|
||||
Decodes blocks of data
|
||||
*****************************************************************************************/
|
||||
int CAPEDecompress::GetBlocks(unsigned char * pOutputBuffer, int nBlocks)
|
||||
{
|
||||
if (nBlocks <= 0) return 0;
|
||||
|
||||
int nRetVal = ERROR_SUCCESS;
|
||||
int nBlocksLeft = nBlocks;
|
||||
|
||||
while (nBlocksLeft > 0)
|
||||
{
|
||||
// start of frame code
|
||||
if (m_nBlocksProcessed == 0)
|
||||
{
|
||||
if (StartFrame() != 0)
|
||||
{
|
||||
m_bCurrentFrameCorrupt = TRUE;
|
||||
nRetVal = -1;
|
||||
}
|
||||
}
|
||||
|
||||
// get the blocks (up to the end of the frame)
|
||||
|
||||
const int nBlocksUntilEndOfFrame = GetInfo(APE_INFO_BLOCKS_PER_FRAME) - m_nBlocksProcessed;
|
||||
const int nBlocksThisPass = min(nBlocksLeft, nBlocksUntilEndOfFrame);
|
||||
|
||||
int nBlocksProcessed = 0;
|
||||
|
||||
if (m_bCurrentFrameCorrupt)
|
||||
{
|
||||
for (nBlocksProcessed = 0; nBlocksProcessed < nBlocksThisPass; nBlocksProcessed++)
|
||||
{
|
||||
m_Prepare.Unprepare(0, 0, &m_wfeInput, pOutputBuffer, &m_nCRC);
|
||||
m_nBlocksProcessed++;
|
||||
}
|
||||
nBlocksLeft -= nBlocksProcessed;
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
if (m_wfeInput.nChannels == 2)
|
||||
{
|
||||
if ((m_nSpecialCodes & SPECIAL_FRAME_LEFT_SILENCE) &&
|
||||
(m_nSpecialCodes & SPECIAL_FRAME_RIGHT_SILENCE))
|
||||
{
|
||||
for (nBlocksProcessed = 0; nBlocksProcessed < nBlocksThisPass; nBlocksProcessed++)
|
||||
{
|
||||
m_Prepare.Unprepare(0, 0, &m_wfeInput, pOutputBuffer, &m_nCRC);
|
||||
pOutputBuffer += m_nBlockAlign;
|
||||
m_nBlocksProcessed++;
|
||||
}
|
||||
}
|
||||
else if (m_nSpecialCodes & SPECIAL_FRAME_PSEUDO_STEREO)
|
||||
{
|
||||
for (nBlocksProcessed = 0; nBlocksProcessed < nBlocksThisPass; nBlocksProcessed++)
|
||||
{
|
||||
int X = m_spNewPredictorX->DecompressValue(m_spUnBitArray->DecodeValueRange(m_BitArrayStateX));
|
||||
m_Prepare.Unprepare(X, 0, &m_wfeInput, pOutputBuffer, &m_nCRC);
|
||||
pOutputBuffer += m_nBlockAlign;
|
||||
m_nBlocksProcessed++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_spAPEInfo->GetInfo(APE_INFO_FILE_VERSION) >= 3950)
|
||||
{
|
||||
for (nBlocksProcessed = 0; nBlocksProcessed < nBlocksThisPass; nBlocksProcessed++)
|
||||
{
|
||||
int nY = m_spUnBitArray->DecodeValueRange(m_BitArrayStateY);
|
||||
int nX = m_spUnBitArray->DecodeValueRange(m_BitArrayStateX);
|
||||
int Y = m_spNewPredictorY->DecompressValue(nY, m_nLastX);
|
||||
int X = m_spNewPredictorX->DecompressValue(nX, Y);
|
||||
m_nLastX = X;
|
||||
|
||||
m_Prepare.Unprepare(X, Y, &m_wfeInput, pOutputBuffer, &m_nCRC);
|
||||
pOutputBuffer += m_nBlockAlign;
|
||||
m_nBlocksProcessed++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (nBlocksProcessed = 0; nBlocksProcessed < nBlocksThisPass; nBlocksProcessed++)
|
||||
{
|
||||
int X = m_spNewPredictorX->DecompressValue(m_spUnBitArray->DecodeValueRange(m_BitArrayStateX));
|
||||
int Y = m_spNewPredictorY->DecompressValue(m_spUnBitArray->DecodeValueRange(m_BitArrayStateY));
|
||||
m_Prepare.Unprepare(X, Y, &m_wfeInput, pOutputBuffer, &m_nCRC);
|
||||
pOutputBuffer += m_nBlockAlign;
|
||||
m_nBlocksProcessed++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_nSpecialCodes & SPECIAL_FRAME_MONO_SILENCE)
|
||||
{
|
||||
for (nBlocksProcessed = 0; nBlocksProcessed < nBlocksThisPass; nBlocksProcessed++)
|
||||
{
|
||||
m_Prepare.Unprepare(0, 0, &m_wfeInput, pOutputBuffer, &m_nCRC);
|
||||
pOutputBuffer += m_nBlockAlign;
|
||||
m_nBlocksProcessed++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (nBlocksProcessed = 0; nBlocksProcessed < nBlocksThisPass; nBlocksProcessed++)
|
||||
{
|
||||
int X = m_spNewPredictorX->DecompressValue(m_spUnBitArray->DecodeValueRange(m_BitArrayStateX));
|
||||
m_Prepare.Unprepare(X, 0, &m_wfeInput, pOutputBuffer, &m_nCRC);
|
||||
pOutputBuffer += m_nBlockAlign;
|
||||
m_nBlocksProcessed++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nBlocksLeft -= nBlocksProcessed;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
m_bCurrentFrameCorrupt = TRUE;
|
||||
nRetVal = -1;
|
||||
nBlocksLeft -= nBlocksProcessed;
|
||||
}
|
||||
}
|
||||
|
||||
// end of frame code
|
||||
if (m_nBlocksProcessed == GetInfo(APE_INFO_BLOCKS_PER_FRAME))
|
||||
{
|
||||
if (EndFrame() != 0)
|
||||
nRetVal = -1;
|
||||
}
|
||||
}
|
||||
|
||||
return nRetVal;
|
||||
}
|
||||
|
||||
int CAPEDecompress::StartFrame()
|
||||
{
|
||||
m_nCRC = 0xFFFFFFFF;
|
||||
|
||||
// get the frame header
|
||||
m_nStoredCRC = m_spUnBitArray->DecodeValue(DECODE_VALUE_METHOD_UNSIGNED_INT);
|
||||
|
||||
//get any 'special' codes if the file uses them (for silence, FALSE stereo, etc.)
|
||||
m_nSpecialCodes = 0;
|
||||
if (GET_USES_SPECIAL_FRAMES(m_spAPEInfo))
|
||||
{
|
||||
if (m_nStoredCRC & 0x80000000)
|
||||
{
|
||||
m_nSpecialCodes = m_spUnBitArray->DecodeValue(DECODE_VALUE_METHOD_UNSIGNED_INT);
|
||||
}
|
||||
m_nStoredCRC &= 0x7fffffff;
|
||||
}
|
||||
|
||||
m_spNewPredictorX->Flush();
|
||||
m_spNewPredictorY->Flush();
|
||||
|
||||
m_spUnBitArray->FlushState(m_BitArrayStateX);
|
||||
m_spUnBitArray->FlushState(m_BitArrayStateY);
|
||||
|
||||
m_spUnBitArray->FlushBitArray();
|
||||
|
||||
m_bCurrentFrameCorrupt = FALSE;
|
||||
|
||||
m_nLastX = 0;
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
int CAPEDecompress::EndFrame()
|
||||
{
|
||||
int nRetVal = ERROR_SUCCESS;
|
||||
|
||||
m_nCurrentFrame++;
|
||||
m_nBlocksProcessed = 0;
|
||||
|
||||
if (m_bCurrentFrameCorrupt == FALSE)
|
||||
{
|
||||
// finalize
|
||||
m_spUnBitArray->Finalize();
|
||||
|
||||
// check the CRC
|
||||
m_nCRC = m_nCRC ^ 0xFFFFFFFF;
|
||||
m_nCRC >>= 1;
|
||||
if (m_nCRC != m_nStoredCRC)
|
||||
{
|
||||
nRetVal = -1;
|
||||
m_bCurrentFrameCorrupt = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_bCurrentFrameCorrupt)
|
||||
{
|
||||
SeekToFrame(m_nCurrentFrame);
|
||||
}
|
||||
|
||||
return nRetVal;
|
||||
}
|
||||
|
||||
/*****************************************************************************************
|
||||
Seek to the proper frame (if necessary) and do any alignment of the bit array
|
||||
*****************************************************************************************/
|
||||
int CAPEDecompress::SeekToFrame(int nFrameIndex)
|
||||
{
|
||||
int nSeekRemainder = (GetInfo(APE_INFO_SEEK_BYTE, nFrameIndex) - GetInfo(APE_INFO_SEEK_BYTE, 0)) % 4;
|
||||
return m_spUnBitArray->FillAndResetBitArray(GetInfo(APE_INFO_SEEK_BYTE, nFrameIndex) - nSeekRemainder, nSeekRemainder * 8);
|
||||
}
|
||||
|
||||
/*****************************************************************************************
|
||||
Get information from the decompressor
|
||||
*****************************************************************************************/
|
||||
int CAPEDecompress::GetInfo(APE_DECOMPRESS_FIELDS Field, int nParam1, int nParam2)
|
||||
{
|
||||
int nRetVal = 0;
|
||||
BOOL bHandled = TRUE;
|
||||
|
||||
switch (Field)
|
||||
{
|
||||
case APE_DECOMPRESS_CURRENT_BLOCK:
|
||||
nRetVal = m_nCurrentBlock - m_nStartBlock;
|
||||
break;
|
||||
case APE_DECOMPRESS_CURRENT_MS:
|
||||
{
|
||||
int nSampleRate = m_spAPEInfo->GetInfo(APE_INFO_SAMPLE_RATE, 0, 0);
|
||||
if (nSampleRate > 0)
|
||||
nRetVal = int((double(m_nCurrentBlock) * double(1000)) / double(nSampleRate));
|
||||
break;
|
||||
}
|
||||
case APE_DECOMPRESS_TOTAL_BLOCKS:
|
||||
nRetVal = m_nFinishBlock - m_nStartBlock;
|
||||
break;
|
||||
case APE_DECOMPRESS_LENGTH_MS:
|
||||
{
|
||||
int nSampleRate = m_spAPEInfo->GetInfo(APE_INFO_SAMPLE_RATE, 0, 0);
|
||||
if (nSampleRate > 0)
|
||||
nRetVal = int((double(m_nFinishBlock - m_nStartBlock) * double(1000)) / double(nSampleRate));
|
||||
break;
|
||||
}
|
||||
case APE_DECOMPRESS_CURRENT_BITRATE:
|
||||
nRetVal = GetInfo(APE_INFO_FRAME_BITRATE, m_nCurrentFrame);
|
||||
break;
|
||||
case APE_DECOMPRESS_AVERAGE_BITRATE:
|
||||
{
|
||||
if (m_bIsRanged)
|
||||
{
|
||||
// figure the frame range
|
||||
const int nBlocksPerFrame = GetInfo(APE_INFO_BLOCKS_PER_FRAME);
|
||||
int nStartFrame = m_nStartBlock / nBlocksPerFrame;
|
||||
int nFinishFrame = (m_nFinishBlock + nBlocksPerFrame - 1) / nBlocksPerFrame;
|
||||
|
||||
// get the number of bytes in the first and last frame
|
||||
int nTotalBytes = (GetInfo(APE_INFO_FRAME_BYTES, nStartFrame) * (m_nStartBlock % nBlocksPerFrame)) / nBlocksPerFrame;
|
||||
if (nFinishFrame != nStartFrame)
|
||||
nTotalBytes += (GetInfo(APE_INFO_FRAME_BYTES, nFinishFrame) * (m_nFinishBlock % nBlocksPerFrame)) / nBlocksPerFrame;
|
||||
|
||||
// get the number of bytes in between
|
||||
const int nTotalFrames = GetInfo(APE_INFO_TOTAL_FRAMES);
|
||||
for (int nFrame = nStartFrame + 1; (nFrame < nFinishFrame) && (nFrame < nTotalFrames); nFrame++)
|
||||
nTotalBytes += GetInfo(APE_INFO_FRAME_BYTES, nFrame);
|
||||
|
||||
// figure the bitrate
|
||||
int nTotalMS = int((double(m_nFinishBlock - m_nStartBlock) * double(1000)) / double(GetInfo(APE_INFO_SAMPLE_RATE)));
|
||||
if (nTotalMS != 0)
|
||||
nRetVal = (nTotalBytes * 8) / nTotalMS;
|
||||
}
|
||||
else
|
||||
{
|
||||
nRetVal = GetInfo(APE_INFO_AVERAGE_BITRATE);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
bHandled = FALSE;
|
||||
}
|
||||
|
||||
if (!bHandled && m_bIsRanged)
|
||||
{
|
||||
bHandled = TRUE;
|
||||
|
||||
switch (Field)
|
||||
{
|
||||
case APE_INFO_WAV_HEADER_BYTES:
|
||||
nRetVal = sizeof(WAVE_HEADER);
|
||||
break;
|
||||
case APE_INFO_WAV_HEADER_DATA:
|
||||
{
|
||||
char * pBuffer = (char *) nParam1;
|
||||
int nMaxBytes = nParam2;
|
||||
|
||||
if (sizeof(WAVE_HEADER) > nMaxBytes)
|
||||
{
|
||||
nRetVal = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
WAVEFORMATEX wfeFormat; GetInfo(APE_INFO_WAVEFORMATEX, (int) &wfeFormat, 0);
|
||||
WAVE_HEADER WAVHeader; FillWaveHeader(&WAVHeader,
|
||||
(m_nFinishBlock - m_nStartBlock) * GetInfo(APE_INFO_BLOCK_ALIGN),
|
||||
&wfeFormat, 0);
|
||||
memcpy(pBuffer, &WAVHeader, sizeof(WAVE_HEADER));
|
||||
nRetVal = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case APE_INFO_WAV_TERMINATING_BYTES:
|
||||
nRetVal = 0;
|
||||
break;
|
||||
case APE_INFO_WAV_TERMINATING_DATA:
|
||||
nRetVal = 0;
|
||||
break;
|
||||
default:
|
||||
bHandled = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (bHandled == FALSE)
|
||||
nRetVal = m_spAPEInfo->GetInfo(Field, nParam1, nParam2);
|
||||
|
||||
return nRetVal;
|
||||
}
|
65
gst/monkeyaudio/libmonkeyaudio/APEDecompress.h
Normal file
65
gst/monkeyaudio/libmonkeyaudio/APEDecompress.h
Normal file
|
@ -0,0 +1,65 @@
|
|||
#ifndef APE_DECOMPRESS_H
|
||||
#define APE_DECOMPRESS_H
|
||||
|
||||
#include "APEDecompress.h"
|
||||
|
||||
class CUnBitArray;
|
||||
class CPrepare;
|
||||
class CAPEInfo;
|
||||
class IPredictorDecompress;
|
||||
#include "UnBitArrayBase.h"
|
||||
#include "MACLib.h"
|
||||
#include "Prepare.h"
|
||||
|
||||
class CAPEDecompress : public IAPEDecompress
|
||||
{
|
||||
public:
|
||||
CAPEDecompress(int * pErrorCode, CAPEInfo * pAPEInfo, int nStartBlock = -1, int nFinishBlock = -1);
|
||||
~CAPEDecompress();
|
||||
|
||||
int GetData(char * pBuffer, int nBlocks, int * pBlocksRetrieved);
|
||||
int Seek(int nBlockOffset);
|
||||
|
||||
int GetInfo(APE_DECOMPRESS_FIELDS Field, int nParam1 = 0, int nParam2 = 0);
|
||||
|
||||
protected:
|
||||
|
||||
// file info
|
||||
int m_nBlockAlign;
|
||||
int m_nCurrentFrame;
|
||||
|
||||
// start / finish information
|
||||
int m_nStartBlock;
|
||||
int m_nFinishBlock;
|
||||
int m_nCurrentBlock;
|
||||
BOOL m_bIsRanged;
|
||||
BOOL m_bDecompressorInitialized;
|
||||
|
||||
// decoding tools
|
||||
CPrepare m_Prepare;
|
||||
WAVEFORMATEX m_wfeInput;
|
||||
int m_nBlocksProcessed;
|
||||
unsigned int m_nCRC;
|
||||
unsigned int m_nStoredCRC;
|
||||
int m_nSpecialCodes;
|
||||
BOOL m_bCurrentFrameCorrupt;
|
||||
|
||||
int SeekToFrame(int nFrameIndex);
|
||||
int GetBlocks(unsigned char * pOutputBuffer, int nBlocks);
|
||||
int StartFrame();
|
||||
int EndFrame();
|
||||
int InitializeDecompressor();
|
||||
|
||||
// more decoding components
|
||||
CSmartPtr<CAPEInfo> m_spAPEInfo;
|
||||
CSmartPtr<CUnBitArrayBase> m_spUnBitArray;
|
||||
BIT_ARRAY_STATE m_BitArrayStateX;
|
||||
BIT_ARRAY_STATE m_BitArrayStateY;
|
||||
|
||||
CSmartPtr<IPredictorDecompress> m_spNewPredictorX;
|
||||
CSmartPtr<IPredictorDecompress> m_spNewPredictorY;
|
||||
|
||||
int m_nLastX;
|
||||
};
|
||||
|
||||
#endif /* APE_DECOMPRESS_H */
|
495
gst/monkeyaudio/libmonkeyaudio/APEInfo.cpp
Normal file
495
gst/monkeyaudio/libmonkeyaudio/APEInfo.cpp
Normal file
|
@ -0,0 +1,495 @@
|
|||
/*****************************************************************************************
|
||||
CAPEInfo:
|
||||
-a class to make working with APE files and getting information about them simple
|
||||
*****************************************************************************************/
|
||||
#include "All.h"
|
||||
#include "APEInfo.h"
|
||||
#include IO_HEADER_FILE
|
||||
#include "APECompress.h"
|
||||
|
||||
/*****************************************************************************************
|
||||
Construction
|
||||
*****************************************************************************************/
|
||||
CAPEInfo::CAPEInfo(int * pErrorCode, const char * pFilename, CAPETag * pTag)
|
||||
{
|
||||
*pErrorCode = ERROR_SUCCESS;
|
||||
CloseFile();
|
||||
|
||||
// open the file
|
||||
m_spIO.Assign(new IO_CLASS_NAME);
|
||||
|
||||
if (m_spIO->Open(pFilename) != 0)
|
||||
{
|
||||
CloseFile();
|
||||
*pErrorCode = ERROR_INVALID_INPUT_FILE;
|
||||
return;
|
||||
}
|
||||
|
||||
// get the file information
|
||||
if (GetFileInformation(TRUE) != 0)
|
||||
{
|
||||
CloseFile();
|
||||
*pErrorCode = ERROR_INVALID_INPUT_FILE;
|
||||
return;
|
||||
}
|
||||
|
||||
// get the tag (do this second so that we don't do it on failure)
|
||||
if (pTag == NULL)
|
||||
m_spAPETag.Assign(new CAPETag(m_spIO, TRUE));
|
||||
else
|
||||
m_spAPETag.Assign(pTag);
|
||||
|
||||
}
|
||||
|
||||
CAPEInfo::CAPEInfo(int * pErrorCode, CIO *pIO, CAPETag * pTag)
|
||||
{
|
||||
*pErrorCode = ERROR_SUCCESS;
|
||||
CloseFile();
|
||||
|
||||
m_spIO.Assign(pIO, FALSE, FALSE);
|
||||
|
||||
// get the file information
|
||||
if (GetFileInformation(TRUE) != 0)
|
||||
{
|
||||
CloseFile();
|
||||
*pErrorCode = ERROR_INVALID_INPUT_FILE;
|
||||
return;
|
||||
}
|
||||
|
||||
// get the tag (do this second so that we don't do it on failure)
|
||||
if (pTag == NULL)
|
||||
m_spAPETag.Assign(new CAPETag(m_spIO, TRUE));
|
||||
else
|
||||
m_spAPETag.Assign(pTag);
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************************
|
||||
Destruction
|
||||
*****************************************************************************************/
|
||||
CAPEInfo::~CAPEInfo()
|
||||
{
|
||||
CloseFile();
|
||||
}
|
||||
|
||||
/*****************************************************************************************
|
||||
Close the file
|
||||
*****************************************************************************************/
|
||||
int CAPEInfo::CloseFile()
|
||||
{
|
||||
m_spIO.Delete();
|
||||
m_spWaveHeaderData.Delete();
|
||||
m_spSeekBitTable.Delete();
|
||||
m_spSeekByteTable.Delete();
|
||||
m_spAPETag.Delete();
|
||||
|
||||
// re-initialize variables
|
||||
m_nSeekTableElements = 0;
|
||||
m_bHasFileInformationLoaded = FALSE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*****************************************************************************************
|
||||
Get the file information about the file
|
||||
*****************************************************************************************/
|
||||
int CAPEInfo::GetFileInformation(BOOL bGetTagInformation)
|
||||
{
|
||||
// quit if there is no simple file
|
||||
if (m_spIO == NULL) { return -1; }
|
||||
|
||||
// quit if the file information has already been loaded
|
||||
if (m_bHasFileInformationLoaded) { return 0; }
|
||||
|
||||
// variable declares
|
||||
unsigned int BytesRead = 0;
|
||||
|
||||
// read the MAC header from the file
|
||||
int nOriginalFileLocation = m_spIO->GetPosition();
|
||||
|
||||
// get to the beginning of the APE file (skip ID3v2, etc.)
|
||||
m_spIO->Seek(0, FILE_BEGIN);
|
||||
|
||||
int nRetVal = SkipToAPEHeader();
|
||||
if (nRetVal != ERROR_SUCCESS) return nRetVal;
|
||||
|
||||
APE_HEADER APEHeader;
|
||||
m_spIO->Read((unsigned char *) &APEHeader, APE_HEADER_BYTES, &BytesRead);
|
||||
|
||||
// fail on 0 length APE files (catches non-finalized APE files)
|
||||
if (APEHeader.nTotalFrames == 0)
|
||||
return -1;
|
||||
|
||||
int nPeakLevel = -1;
|
||||
if (APEHeader.nFormatFlags & MAC_FORMAT_FLAG_HAS_PEAK_LEVEL)
|
||||
m_spIO->Read((unsigned char *) &nPeakLevel, 4, &BytesRead);
|
||||
|
||||
if (APEHeader.nFormatFlags & MAC_FORMAT_FLAG_HAS_SEEK_ELEMENTS)
|
||||
m_spIO->Read((unsigned char *) &m_nSeekTableElements, 4, &BytesRead);
|
||||
else
|
||||
m_nSeekTableElements = APEHeader.nTotalFrames;
|
||||
|
||||
// fill the APE info structure
|
||||
m_APEFileInfo.nVersion = int(APEHeader.nVersion);
|
||||
m_APEFileInfo.nCompressionLevel = int(APEHeader.nCompressionLevel);
|
||||
m_APEFileInfo.nFormatFlags = int(APEHeader.nFormatFlags);
|
||||
m_APEFileInfo.nTotalFrames = int(APEHeader.nTotalFrames);
|
||||
m_APEFileInfo.nFinalFrameBlocks = int(APEHeader.nFinalFrameBlocks);
|
||||
m_APEFileInfo.nBlocksPerFrame = ((APEHeader.nVersion >= 3900) || ((APEHeader.nVersion >= 3800) && (APEHeader.nCompressionLevel == COMPRESSION_LEVEL_EXTRA_HIGH))) ? 0x12000 : 0x02400;
|
||||
if ((APEHeader.nVersion >= 3950)) m_APEFileInfo.nBlocksPerFrame = 0x48000;
|
||||
m_APEFileInfo.nChannels = int(APEHeader.nChannels);
|
||||
m_APEFileInfo.nSampleRate = int(APEHeader.nSampleRate);
|
||||
m_APEFileInfo.nBitsPerSample = (m_APEFileInfo.nFormatFlags & MAC_FORMAT_FLAG_8_BIT) ? 8 : ((m_APEFileInfo.nFormatFlags & MAC_FORMAT_FLAG_24_BIT) ? 24 : 16);
|
||||
m_APEFileInfo.nBytesPerSample = m_APEFileInfo.nBitsPerSample / 8;
|
||||
m_APEFileInfo.nBlockAlign = m_APEFileInfo.nBytesPerSample * m_APEFileInfo.nChannels;
|
||||
m_APEFileInfo.nTotalBlocks = (APEHeader.nTotalFrames == 0) ? 0 : ((APEHeader.nTotalFrames - 1) * m_APEFileInfo.nBlocksPerFrame) + APEHeader.nFinalFrameBlocks;
|
||||
m_APEFileInfo.nWAVHeaderBytes = (APEHeader.nFormatFlags & MAC_FORMAT_FLAG_CREATE_WAV_HEADER) ? sizeof(WAVE_HEADER) : APEHeader.nHeaderBytes;
|
||||
m_APEFileInfo.nWAVTerminatingBytes = int(APEHeader.nTerminatingBytes);
|
||||
m_APEFileInfo.nWAVDataBytes = m_APEFileInfo.nTotalBlocks * m_APEFileInfo.nBlockAlign;
|
||||
m_APEFileInfo.nWAVTotalBytes = m_APEFileInfo.nWAVDataBytes + m_APEFileInfo.nWAVHeaderBytes + m_APEFileInfo.nWAVTerminatingBytes;
|
||||
m_APEFileInfo.nAPETotalBytes = m_spIO->GetSize();
|
||||
m_APEFileInfo.nLengthMS = int((double(m_APEFileInfo.nTotalBlocks) * double(1000)) / double(m_APEFileInfo.nSampleRate));
|
||||
m_APEFileInfo.nAverageBitrate = (m_APEFileInfo.nLengthMS <= 0) ? 0 : int((double(m_APEFileInfo.nAPETotalBytes) * double(8)) / double(m_APEFileInfo.nLengthMS));
|
||||
m_APEFileInfo.nDecompressedBitrate = (m_APEFileInfo.nBlockAlign * m_APEFileInfo.nSampleRate * 8) / 1000;
|
||||
m_APEFileInfo.nPeakLevel = nPeakLevel;
|
||||
|
||||
// get the wave header
|
||||
if (!(APEHeader.nFormatFlags & MAC_FORMAT_FLAG_CREATE_WAV_HEADER))
|
||||
{
|
||||
m_spWaveHeaderData.Assign(new unsigned char [APEHeader.nHeaderBytes], TRUE);
|
||||
if (m_spWaveHeaderData == NULL) { return -1; }
|
||||
m_spIO->Read((unsigned char *) m_spWaveHeaderData, APEHeader.nHeaderBytes, &BytesRead);
|
||||
}
|
||||
|
||||
// get the seek tables (really no reason to get the whole thing if there's extra)
|
||||
m_spSeekByteTable.Assign(new unsigned __int32 [m_nSeekTableElements], TRUE);
|
||||
if (m_spSeekByteTable == NULL) { return -1; }
|
||||
|
||||
m_spIO->Read((unsigned char *) m_spSeekByteTable.GetPtr(), 4 * m_nSeekTableElements, &BytesRead);
|
||||
|
||||
if (APEHeader.nVersion <= 3800)
|
||||
{
|
||||
m_spSeekBitTable.Assign(new unsigned char [m_nSeekTableElements], TRUE);
|
||||
if (m_spSeekBitTable == NULL) { return -1; }
|
||||
|
||||
m_spIO->Read((unsigned char *) m_spSeekBitTable, m_nSeekTableElements, &BytesRead);
|
||||
}
|
||||
|
||||
m_spIO->Seek(nOriginalFileLocation, FILE_BEGIN);
|
||||
|
||||
m_bHasFileInformationLoaded = TRUE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CAPEInfo::SkipToAPEHeader()
|
||||
{
|
||||
// reset
|
||||
m_nExtraHeaderBytes = 0;
|
||||
|
||||
// figure the extra header bytes
|
||||
|
||||
// skip an ID3v2 tag (which we really don't support anyway...)
|
||||
unsigned int nBytesRead = 0;
|
||||
unsigned char cID3v2Header[10];
|
||||
m_spIO->Read((unsigned char *) cID3v2Header, 10, &nBytesRead);
|
||||
if (cID3v2Header[0] == 'I' && cID3v2Header[1] == 'D' && cID3v2Header[2] == '3')
|
||||
{
|
||||
// why is it so hard to figure the lenght of an ID3v2 tag ?!?
|
||||
unsigned int nLength = *((unsigned int *) &cID3v2Header[6]);
|
||||
|
||||
unsigned int nSyncSafeLength = 0;
|
||||
nSyncSafeLength = (cID3v2Header[6] & 127) << 21;
|
||||
nSyncSafeLength += (cID3v2Header[7] & 127) << 14;
|
||||
nSyncSafeLength += (cID3v2Header[8] & 127) << 7;
|
||||
nSyncSafeLength += (cID3v2Header[9] & 127);
|
||||
|
||||
BOOL bHasTagFooter = FALSE;
|
||||
|
||||
if (cID3v2Header[5] & 16)
|
||||
{
|
||||
bHasTagFooter = TRUE;
|
||||
m_nExtraHeaderBytes = nSyncSafeLength + 20;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_nExtraHeaderBytes = nSyncSafeLength + 10;
|
||||
}
|
||||
|
||||
// error check
|
||||
if (cID3v2Header[5] & 64)
|
||||
{
|
||||
// this ID3v2 length calculator algorithm can't cope with extended headers
|
||||
// we should be ok though, because the scan for the MAC header below should
|
||||
// really do the trick
|
||||
}
|
||||
|
||||
m_spIO->Seek(m_nExtraHeaderBytes, FILE_BEGIN);
|
||||
|
||||
// scan for padding (slow and stupid, but who cares here...)
|
||||
if (!bHasTagFooter)
|
||||
{
|
||||
char cTemp = 0;
|
||||
m_spIO->Read((unsigned char *) &cTemp, 1, &nBytesRead);
|
||||
while (cTemp == 0 && nBytesRead == 1)
|
||||
{
|
||||
m_nExtraHeaderBytes++;
|
||||
m_spIO->Read((unsigned char *) &cTemp, 1, &nBytesRead);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_spIO->Seek(m_nExtraHeaderBytes, FILE_BEGIN);
|
||||
|
||||
// scan until we hit the APE header, the end of the file, or 1 MB later
|
||||
unsigned int nGoalID = (' ' << 24) | ('C' << 16) | ('A' << 8) | ('M');
|
||||
unsigned int nReadID = 0;
|
||||
int nRetVal = m_spIO->Read(&nReadID, 4, &nBytesRead);
|
||||
if (nRetVal != 0 || nBytesRead != 4) return -1;
|
||||
|
||||
nBytesRead = 1;
|
||||
int nScanBytes = 0;
|
||||
while (nGoalID != nReadID && nBytesRead == 1 && nScanBytes < (1024 * 1024))
|
||||
{
|
||||
unsigned char cTemp;
|
||||
m_spIO->Read(&cTemp, 1, &nBytesRead);
|
||||
nReadID = (((unsigned int) cTemp) << 24) | (nReadID >> 8);
|
||||
m_nExtraHeaderBytes++;
|
||||
nScanBytes++;
|
||||
}
|
||||
|
||||
if (nGoalID != nReadID)
|
||||
return -1;
|
||||
|
||||
// successfully found the start of the file (seek to it and return)
|
||||
m_spIO->Seek(m_nExtraHeaderBytes, FILE_BEGIN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CAPEInfo::GetInfo(APE_DECOMPRESS_FIELDS Field, int nParam1, int nParam2)
|
||||
{
|
||||
int nRetVal = -1;
|
||||
|
||||
switch (Field)
|
||||
{
|
||||
case APE_INFO_FILE_VERSION:
|
||||
nRetVal = m_APEFileInfo.nVersion;
|
||||
break;
|
||||
case APE_INFO_COMPRESSION_LEVEL:
|
||||
nRetVal = m_APEFileInfo.nCompressionLevel;
|
||||
break;
|
||||
case APE_INFO_FORMAT_FLAGS:
|
||||
nRetVal = m_APEFileInfo.nFormatFlags;
|
||||
break;
|
||||
case APE_INFO_SAMPLE_RATE:
|
||||
nRetVal = m_APEFileInfo.nSampleRate;
|
||||
break;
|
||||
case APE_INFO_BITS_PER_SAMPLE:
|
||||
nRetVal = m_APEFileInfo.nBitsPerSample;
|
||||
break;
|
||||
case APE_INFO_BYTES_PER_SAMPLE:
|
||||
nRetVal = m_APEFileInfo.nBytesPerSample;
|
||||
break;
|
||||
case APE_INFO_CHANNELS:
|
||||
nRetVal = m_APEFileInfo.nChannels;
|
||||
break;
|
||||
case APE_INFO_BLOCK_ALIGN:
|
||||
nRetVal = m_APEFileInfo.nBlockAlign;
|
||||
break;
|
||||
case APE_INFO_BLOCKS_PER_FRAME:
|
||||
nRetVal = m_APEFileInfo.nBlocksPerFrame;
|
||||
break;
|
||||
case APE_INFO_FINAL_FRAME_BLOCKS:
|
||||
nRetVal = m_APEFileInfo.nFinalFrameBlocks;
|
||||
break;
|
||||
case APE_INFO_TOTAL_FRAMES:
|
||||
nRetVal = m_APEFileInfo.nTotalFrames;
|
||||
break;
|
||||
case APE_INFO_WAV_HEADER_BYTES:
|
||||
nRetVal = m_APEFileInfo.nWAVHeaderBytes;
|
||||
break;
|
||||
case APE_INFO_WAV_TERMINATING_BYTES:
|
||||
nRetVal = m_APEFileInfo.nWAVTerminatingBytes;
|
||||
break;
|
||||
case APE_INFO_WAV_DATA_BYTES:
|
||||
nRetVal = m_APEFileInfo.nWAVDataBytes;
|
||||
break;
|
||||
case APE_INFO_WAV_TOTAL_BYTES:
|
||||
nRetVal = m_APEFileInfo.nWAVTotalBytes;
|
||||
break;
|
||||
case APE_INFO_APE_TOTAL_BYTES:
|
||||
nRetVal = m_APEFileInfo.nAPETotalBytes;
|
||||
break;
|
||||
case APE_INFO_TOTAL_BLOCKS:
|
||||
nRetVal = m_APEFileInfo.nTotalBlocks;
|
||||
break;
|
||||
case APE_INFO_LENGTH_MS:
|
||||
nRetVal = m_APEFileInfo.nLengthMS;
|
||||
break;
|
||||
case APE_INFO_AVERAGE_BITRATE:
|
||||
nRetVal = m_APEFileInfo.nAverageBitrate;
|
||||
break;
|
||||
case APE_INFO_FRAME_BITRATE:
|
||||
{
|
||||
int nFrame = nParam1;
|
||||
|
||||
nRetVal = 0;
|
||||
|
||||
int nFrameBytes = GetInfo(APE_INFO_FRAME_BYTES, nFrame);
|
||||
int nFrameBlocks = GetInfo(APE_INFO_FRAME_BLOCKS, nFrame);
|
||||
if ((nFrameBytes > 0) && (nFrameBlocks > 0) && m_APEFileInfo.nSampleRate > 0)
|
||||
{
|
||||
int nFrameMS = (nFrameBlocks * 1000) / m_APEFileInfo.nSampleRate;
|
||||
if (nFrameMS != 0)
|
||||
{
|
||||
nRetVal = (nFrameBytes * 8) / nFrameMS;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case APE_INFO_DECOMPRESSED_BITRATE:
|
||||
nRetVal = m_APEFileInfo.nDecompressedBitrate;
|
||||
break;
|
||||
case APE_INFO_PEAK_LEVEL:
|
||||
nRetVal = m_APEFileInfo.nPeakLevel;
|
||||
break;
|
||||
case APE_INFO_SEEK_BIT:
|
||||
{
|
||||
int nFrame = nParam1;
|
||||
if (GET_FRAMES_START_ON_BYTES_BOUNDARIES(this))
|
||||
{
|
||||
nRetVal = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (nFrame < 0 || nFrame >= m_APEFileInfo.nTotalFrames)
|
||||
nRetVal = 0;
|
||||
else
|
||||
nRetVal = m_spSeekBitTable[nFrame];
|
||||
}
|
||||
break;
|
||||
}
|
||||
case APE_INFO_SEEK_BYTE:
|
||||
{
|
||||
int nFrame = nParam1;
|
||||
if (nFrame < 0 || nFrame >= m_APEFileInfo.nTotalFrames)
|
||||
nRetVal = 0;
|
||||
else
|
||||
nRetVal = m_spSeekByteTable[nFrame] + m_nExtraHeaderBytes;
|
||||
break;
|
||||
}
|
||||
case APE_INFO_WAV_HEADER_DATA:
|
||||
{
|
||||
char * pBuffer = (char *) nParam1;
|
||||
int nMaxBytes = nParam2;
|
||||
|
||||
if (m_APEFileInfo.nFormatFlags & MAC_FORMAT_FLAG_CREATE_WAV_HEADER)
|
||||
{
|
||||
if (sizeof(WAVE_HEADER) > nMaxBytes)
|
||||
{
|
||||
nRetVal = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
WAVEFORMATEX wfeFormat; GetInfo(APE_INFO_WAVEFORMATEX, (int) &wfeFormat, 0);
|
||||
WAVE_HEADER WAVHeader; FillWaveHeader(&WAVHeader, m_APEFileInfo.nWAVDataBytes, &wfeFormat,
|
||||
m_APEFileInfo.nWAVTerminatingBytes);
|
||||
memcpy(pBuffer, &WAVHeader, sizeof(WAVE_HEADER));
|
||||
nRetVal = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_APEFileInfo.nWAVHeaderBytes > nMaxBytes)
|
||||
{
|
||||
nRetVal = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(pBuffer, m_spWaveHeaderData, m_APEFileInfo.nWAVHeaderBytes);
|
||||
nRetVal = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case APE_INFO_WAV_TERMINATING_DATA:
|
||||
{
|
||||
char * pBuffer = (char *) nParam1;
|
||||
int nMaxBytes = nParam2;
|
||||
|
||||
if (m_APEFileInfo.nWAVTerminatingBytes > nMaxBytes)
|
||||
{
|
||||
nRetVal = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_APEFileInfo.nWAVTerminatingBytes > 0)
|
||||
{
|
||||
// variables
|
||||
int nOriginalFileLocation = m_spIO->GetPosition();
|
||||
unsigned int nBytesRead = 0;
|
||||
|
||||
// check for a tag
|
||||
m_spIO->Seek(-(m_spAPETag->GetTagBytes() + m_APEFileInfo.nWAVTerminatingBytes), FILE_END);
|
||||
m_spIO->Read(pBuffer, m_APEFileInfo.nWAVTerminatingBytes, &nBytesRead);
|
||||
|
||||
// restore the file pointer
|
||||
m_spIO->Seek(nOriginalFileLocation, FILE_BEGIN);
|
||||
}
|
||||
nRetVal = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case APE_INFO_WAVEFORMATEX:
|
||||
{
|
||||
WAVEFORMATEX * pWaveFormatEx = (WAVEFORMATEX *) nParam1;
|
||||
FillWaveFormatEx(pWaveFormatEx, m_APEFileInfo.nSampleRate, m_APEFileInfo.nBitsPerSample, m_APEFileInfo.nChannels);
|
||||
nRetVal = 0;
|
||||
break;
|
||||
}
|
||||
case APE_INFO_IO_SOURCE:
|
||||
nRetVal = (int) m_spIO.GetPtr();
|
||||
break;
|
||||
case APE_INFO_FRAME_BYTES:
|
||||
{
|
||||
int nFrame = nParam1;
|
||||
|
||||
// bound-check the frame index
|
||||
if ((nFrame < 0) || (nFrame >= m_APEFileInfo.nTotalFrames))
|
||||
{
|
||||
nRetVal = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (nFrame != (m_APEFileInfo.nTotalFrames - 1))
|
||||
nRetVal = GetInfo(APE_INFO_SEEK_BYTE, nFrame + 1) - GetInfo(APE_INFO_SEEK_BYTE, nFrame);
|
||||
else
|
||||
nRetVal = m_spIO->GetSize() - m_spAPETag->GetTagBytes() - m_APEFileInfo.nWAVTerminatingBytes - GetInfo(APE_INFO_SEEK_BYTE, nFrame);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case APE_INFO_FRAME_BLOCKS:
|
||||
{
|
||||
int nFrame = nParam1;
|
||||
|
||||
// bound-check the frame index
|
||||
if ((nFrame < 0) || (nFrame >= m_APEFileInfo.nTotalFrames))
|
||||
{
|
||||
nRetVal = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (nFrame != (m_APEFileInfo.nTotalFrames - 1))
|
||||
nRetVal = m_APEFileInfo.nBlocksPerFrame;
|
||||
else
|
||||
nRetVal = m_APEFileInfo.nFinalFrameBlocks;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case APE_INFO_TAG:
|
||||
nRetVal = (int) m_spAPETag.GetPtr();
|
||||
break;
|
||||
}
|
||||
|
||||
return nRetVal;
|
||||
}
|
100
gst/monkeyaudio/libmonkeyaudio/APEInfo.h
Normal file
100
gst/monkeyaudio/libmonkeyaudio/APEInfo.h
Normal file
|
@ -0,0 +1,100 @@
|
|||
/*****************************************************************************************
|
||||
APEInfo.h
|
||||
Copyright (C) 2000 by Matthew T. Ashland All Rights Reserved.
|
||||
|
||||
Simple method for working with APE files... it encapsulates reading, writing and getting
|
||||
file information. Just create a CAPEInfo class, call OpenFile(), and use the class methods
|
||||
to do whatever you need... the destructor will take care of any cleanup
|
||||
|
||||
Notes:
|
||||
-Most all functions return 0 upon success, and some error code (other than 0) on
|
||||
failure. However, all of the file functions that are wrapped from the Win32 API
|
||||
return 0 on failure and some other number on success. This applies to ReadFile,
|
||||
WriteFile, SetFilePointer, etc...
|
||||
|
||||
WARNING:
|
||||
-This class driven system for using Monkey's Audio is still in development, so
|
||||
I can't make any guarantees that the classes and libraries won't change before
|
||||
everything gets finalized. Use them at your own risk
|
||||
*****************************************************************************************/
|
||||
|
||||
#ifndef APE_APEINFO_H
|
||||
#define APE_APEINFO_H
|
||||
|
||||
#include "IO.h"
|
||||
#include "APETag.h"
|
||||
#include "MACLib.h"
|
||||
|
||||
/*****************************************************************************************
|
||||
APE_FILE_INFO - structure which describes most aspects of an APE file
|
||||
(used internally for speed and ease)
|
||||
*****************************************************************************************/
|
||||
struct APE_FILE_INFO
|
||||
{
|
||||
int nVersion; // file version number * 1000 (3.93 = 3930)
|
||||
int nCompressionLevel; // the compression level
|
||||
int nFormatFlags; // format flags
|
||||
int nTotalFrames; // the total number frames (frames are used internally)
|
||||
int nBlocksPerFrame; // the samples in a frame (frames are used internally)
|
||||
int nFinalFrameBlocks; // the number of samples in the final frame
|
||||
int nChannels; // audio channels
|
||||
int nSampleRate; // audio samples per second
|
||||
int nBitsPerSample; // audio bits per sample
|
||||
int nBytesPerSample; // audio bytes per sample
|
||||
int nBlockAlign; // audio block align (channels * bytes per sample)
|
||||
int nWAVHeaderBytes; // header bytes of the original WAV
|
||||
int nWAVDataBytes; // data bytes of the original WAV
|
||||
int nWAVTerminatingBytes; // terminating bytes of the original WAV
|
||||
int nWAVTotalBytes; // total bytes of the original WAV
|
||||
int nAPETotalBytes; // total bytes of the APE file
|
||||
int nTotalBlocks; // the total number audio blocks
|
||||
int nLengthMS; // the length in milliseconds
|
||||
int nAverageBitrate; // the kbps (i.e. 637 kpbs)
|
||||
int nDecompressedBitrate; // the kbps of the decompressed audio (i.e. 1440 kpbs for CD audio)
|
||||
int nPeakLevel; // the peak audio level (-1 if unknown)
|
||||
};
|
||||
|
||||
/*****************************************************************************************
|
||||
Helper macros... sort of hacky...
|
||||
*****************************************************************************************/
|
||||
#define GET_USES_CRC(APE_INFO) (((APE_INFO)->GetInfo(APE_INFO_FORMAT_FLAGS) & MAC_FORMAT_FLAG_CRC) ? TRUE : FALSE)
|
||||
#define GET_FRAMES_START_ON_BYTES_BOUNDARIES(APE_INFO) (((APE_INFO)->GetInfo(APE_INFO_FILE_VERSION) > 3800) ? TRUE : FALSE)
|
||||
#define GET_USES_SPECIAL_FRAMES(APE_INFO) (((APE_INFO)->GetInfo(APE_INFO_FILE_VERSION) > 3820) ? TRUE : FALSE)
|
||||
#define GET_IO(APE_INFO) ((CIO *) (APE_INFO)->GetInfo(APE_INFO_IO_SOURCE))
|
||||
#define GET_TAG(APE_INFO) ((CAPETag *) (APE_INFO)->GetInfo(APE_INFO_TAG))
|
||||
|
||||
/*****************************************************************************************
|
||||
CAPEInfo class... use this for all work with APE files
|
||||
*****************************************************************************************/
|
||||
class CAPEInfo
|
||||
{
|
||||
public:
|
||||
|
||||
// construction and destruction
|
||||
CAPEInfo(int * pErrorCode, const char * pFilename, CAPETag * pTag = NULL);
|
||||
CAPEInfo(int * pErrorCode, CIO *pIO, CAPETag * pTag = NULL);
|
||||
virtual ~CAPEInfo();
|
||||
|
||||
// query for information
|
||||
int GetInfo(APE_DECOMPRESS_FIELDS Field, int nParam1 = 0, int nParam2 = 0);
|
||||
|
||||
private:
|
||||
|
||||
// internal functions
|
||||
int GetFileInformation(BOOL bGetTagInformation = TRUE);
|
||||
int CloseFile();
|
||||
int SkipToAPEHeader();
|
||||
|
||||
// internal variables
|
||||
BOOL m_bHasFileInformationLoaded;
|
||||
CSmartPtr<CIO> m_spIO;
|
||||
CSmartPtr<CAPETag> m_spAPETag;
|
||||
CSmartPtr<unsigned char> m_spWaveHeaderData;
|
||||
CSmartPtr<unsigned __int32> m_spSeekByteTable;
|
||||
CSmartPtr<unsigned char> m_spSeekBitTable;
|
||||
int m_nExtraHeaderBytes; //used for ID3v2, etc.
|
||||
int m_nSeekTableElements;
|
||||
APE_FILE_INFO m_APEFileInfo;
|
||||
};
|
||||
|
||||
#endif /* APE_APEINFO_H */
|
72
gst/monkeyaudio/libmonkeyaudio/APELink.cpp
Normal file
72
gst/monkeyaudio/libmonkeyaudio/APELink.cpp
Normal file
|
@ -0,0 +1,72 @@
|
|||
#include "All.h"
|
||||
#include "APELink.h"
|
||||
#include IO_HEADER_FILE
|
||||
|
||||
#define APE_LINK_HEADER "[Monkey's Audio Image Link File]"
|
||||
#define APE_LINK_IMAGE_FILE_TAG "Image File="
|
||||
#define APE_LINK_START_BLOCK_TAG "Start Block="
|
||||
#define APE_LINK_FINISH_BLOCK_TAG "Finish Block="
|
||||
|
||||
CAPELink::CAPELink(const char * pFilename)
|
||||
{
|
||||
// empty
|
||||
m_nStartBlock = 0;
|
||||
m_nFinishBlock = 0;
|
||||
m_cImageFile[0] = 0;
|
||||
|
||||
// open the file
|
||||
IO_CLASS_NAME ioLinkFile;
|
||||
if (ioLinkFile.Open(pFilename) == ERROR_SUCCESS)
|
||||
{
|
||||
// create a buffer
|
||||
CSmartPtr<char> spBuffer(new char [1024], TRUE);
|
||||
|
||||
// fill the buffer from the file and null terminate it
|
||||
unsigned int nBytesRead = 0;
|
||||
ioLinkFile.Read(spBuffer.GetPtr(), 1023, &nBytesRead);
|
||||
spBuffer[nBytesRead] = 0;
|
||||
|
||||
// parse out the information
|
||||
char * pHeader = strstr(spBuffer.GetPtr(), APE_LINK_HEADER);
|
||||
char * pImageFile = strstr(spBuffer.GetPtr(), APE_LINK_IMAGE_FILE_TAG);
|
||||
char * pStartBlock = strstr(spBuffer.GetPtr(), APE_LINK_START_BLOCK_TAG);
|
||||
char * pFinishBlock = strstr(spBuffer.GetPtr(), APE_LINK_FINISH_BLOCK_TAG);
|
||||
|
||||
if (pHeader && pImageFile && pStartBlock && pFinishBlock)
|
||||
{
|
||||
if ((_strnicmp(pHeader, APE_LINK_HEADER, strlen(APE_LINK_HEADER)) == 0) &&
|
||||
(_strnicmp(pImageFile, APE_LINK_IMAGE_FILE_TAG, strlen(APE_LINK_IMAGE_FILE_TAG)) == 0) &&
|
||||
(_strnicmp(pStartBlock, APE_LINK_START_BLOCK_TAG, strlen(APE_LINK_START_BLOCK_TAG)) == 0) &&
|
||||
(_strnicmp(pFinishBlock, APE_LINK_FINISH_BLOCK_TAG, strlen(APE_LINK_FINISH_BLOCK_TAG)) == 0))
|
||||
{
|
||||
// get the start and finish blocks
|
||||
m_nStartBlock = atoi(&pStartBlock[strlen(APE_LINK_START_BLOCK_TAG)]);
|
||||
m_nFinishBlock = atoi(&pFinishBlock[strlen(APE_LINK_FINISH_BLOCK_TAG)]);
|
||||
|
||||
// get the path
|
||||
char cImageFile[MAX_PATH + 1]; int nIndex = 0;
|
||||
char * pImageCharacter = &pImageFile[strlen(APE_LINK_IMAGE_FILE_TAG)];
|
||||
while ((*pImageCharacter != 0) && (*pImageCharacter != '\r') && (*pImageCharacter != '\n'))
|
||||
cImageFile[nIndex++] = *pImageCharacter++;
|
||||
cImageFile[nIndex] = 0;
|
||||
|
||||
// process the path
|
||||
if (strrchr(cImageFile, '\\') == NULL)
|
||||
{
|
||||
char cImagePath[MAX_PATH + 1];
|
||||
strcpy(cImagePath, pFilename);
|
||||
strcpy(strrchr(cImagePath, '\\') + 1, cImageFile);
|
||||
strcpy(m_cImageFile, cImagePath);
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(m_cImageFile, cImageFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CAPELink::~CAPELink()
|
||||
{
|
||||
}
|
20
gst/monkeyaudio/libmonkeyaudio/APELink.h
Normal file
20
gst/monkeyaudio/libmonkeyaudio/APELink.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
#ifndef APE_APELINK_H
|
||||
#define APE_APELINK_H
|
||||
|
||||
#include "IO.h"
|
||||
#include "APEInfo.h"
|
||||
|
||||
class CAPELink
|
||||
{
|
||||
public:
|
||||
CAPELink(const char * pFilename);
|
||||
~CAPELink();
|
||||
|
||||
public:
|
||||
|
||||
int m_nStartBlock;
|
||||
int m_nFinishBlock;
|
||||
char m_cImageFile[MAX_PATH];
|
||||
};
|
||||
|
||||
#endif /* APE_APELINK_H */
|
291
gst/monkeyaudio/libmonkeyaudio/APESimple.cpp
Normal file
291
gst/monkeyaudio/libmonkeyaudio/APESimple.cpp
Normal file
|
@ -0,0 +1,291 @@
|
|||
#include "All.h"
|
||||
|
||||
#include "APEInfo.h"
|
||||
#include "APECompress.h"
|
||||
#include "APEDecompress.h"
|
||||
|
||||
#include "WAVInputSource.h"
|
||||
#include IO_HEADER_FILE
|
||||
#include "MACProgressHelper.h"
|
||||
#include "GlobalFunctions.h"
|
||||
|
||||
#define UNMAC_DECODER_OUTPUT_NONE 0
|
||||
#define UNMAC_DECODER_OUTPUT_WAV 1
|
||||
#define UNMAC_DECODER_OUTPUT_APE 2
|
||||
|
||||
#define BLOCKS_PER_DECODE 9216
|
||||
|
||||
int DecompressCore(const char * pInputFilename, const char * pOutputFilename, int nOutputMode, int nCompressionLevel, int * pPercentageDone, APE_PROGRESS_CALLBACK ProgressCallback, int * pKillFlag);
|
||||
|
||||
/*****************************************************************************************
|
||||
Compress file
|
||||
*****************************************************************************************/
|
||||
int __stdcall CompressFile(const char *pInputFile, const char *pOutputFile, int nCompressionLevel, int *pPercentageDone, APE_PROGRESS_CALLBACK ProgressCallback, int *pKillFlag)
|
||||
{
|
||||
// declare the variables
|
||||
int nFunctionRetVal = ERROR_SUCCESS;
|
||||
WAVEFORMATEX WaveFormatEx;
|
||||
CSmartPtr<CMACProgressHelper> spMACProgressHelper;
|
||||
CSmartPtr<unsigned char> spBuffer;
|
||||
CSmartPtr<IAPECompress> spAPECompress;
|
||||
|
||||
try
|
||||
{
|
||||
// create the input source
|
||||
int nRetVal = ERROR_UNDEFINED;
|
||||
int nAudioBlocks = 0; int nHeaderBytes = 0; int nTerminatingBytes = 0;
|
||||
CSmartPtr<CInputSource> spInputSource(CreateInputSource(pInputFile, &WaveFormatEx, &nAudioBlocks,
|
||||
&nHeaderBytes, &nTerminatingBytes, &nRetVal));
|
||||
|
||||
if ((spInputSource == NULL) || (nRetVal != ERROR_SUCCESS))
|
||||
throw nRetVal;
|
||||
|
||||
// create the compressor
|
||||
spAPECompress.Assign(CreateIAPECompress());
|
||||
if (spAPECompress == NULL) throw ERROR_UNDEFINED;
|
||||
|
||||
// figure the audio bytes
|
||||
int nAudioBytes = nAudioBlocks * WaveFormatEx.nBlockAlign;
|
||||
|
||||
// start the encoder
|
||||
if (nHeaderBytes > 0) spBuffer.Assign(new unsigned char [nHeaderBytes], TRUE);
|
||||
THROW_ON_ERROR(spInputSource->GetHeaderData(spBuffer.GetPtr()))
|
||||
THROW_ON_ERROR(spAPECompress->Start(pOutputFile, &WaveFormatEx, nAudioBytes,
|
||||
nCompressionLevel, spBuffer.GetPtr(), nHeaderBytes));
|
||||
|
||||
spBuffer.Delete();
|
||||
|
||||
// set-up the progress
|
||||
spMACProgressHelper.Assign(new CMACProgressHelper(nAudioBytes, pPercentageDone, ProgressCallback, pKillFlag));
|
||||
|
||||
// master loop
|
||||
int nBytesLeft = nAudioBytes;
|
||||
|
||||
while (nBytesLeft > 0)
|
||||
{
|
||||
int nBytesAdded = 0;
|
||||
THROW_ON_ERROR(spAPECompress->AddDataFromInputSource(spInputSource.GetPtr(), nBytesLeft, &nBytesAdded))
|
||||
|
||||
nBytesLeft -= nBytesAdded;
|
||||
|
||||
// update the progress
|
||||
spMACProgressHelper->UpdateProgress(nAudioBytes - nBytesLeft);
|
||||
|
||||
// process the kill flag
|
||||
if (spMACProgressHelper->ProcessKillFlag(TRUE) != ERROR_SUCCESS)
|
||||
throw(ERROR_USER_STOPPED_PROCESSING);
|
||||
}
|
||||
|
||||
// finalize the file
|
||||
if (nTerminatingBytes > 0) spBuffer.Assign(new unsigned char [nTerminatingBytes], TRUE);
|
||||
THROW_ON_ERROR(spInputSource->GetTerminatingData(spBuffer.GetPtr()));
|
||||
THROW_ON_ERROR(spAPECompress->Finish(spBuffer.GetPtr(), nTerminatingBytes, nTerminatingBytes))
|
||||
|
||||
// update the progress to 100%
|
||||
spMACProgressHelper->UpdateProgressComplete();
|
||||
}
|
||||
catch(int nErrorCode)
|
||||
{
|
||||
nFunctionRetVal = (nErrorCode == 0) ? ERROR_UNDEFINED : nErrorCode;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
nFunctionRetVal = ERROR_UNDEFINED;
|
||||
}
|
||||
|
||||
// kill the compressor if we failed
|
||||
if ((nFunctionRetVal != 0) && (spAPECompress != NULL))
|
||||
spAPECompress->Kill();
|
||||
|
||||
// return
|
||||
return nFunctionRetVal;
|
||||
}
|
||||
|
||||
|
||||
/*****************************************************************************************
|
||||
Verify file
|
||||
*****************************************************************************************/
|
||||
int __stdcall VerifyFile(const char * pInputFilename, int * pPercentageDone, APE_PROGRESS_CALLBACK ProgressCallback, int * pKillFlag)
|
||||
{
|
||||
return DecompressCore(pInputFilename, NULL, UNMAC_DECODER_OUTPUT_NONE, -1, pPercentageDone, ProgressCallback, pKillFlag);
|
||||
}
|
||||
|
||||
/*****************************************************************************************
|
||||
Decompress file
|
||||
*****************************************************************************************/
|
||||
int __stdcall DecompressFile(const char * pInputFilename, const char * pOutputFilename, int * pPercentageDone, APE_PROGRESS_CALLBACK ProgressCallback, int * pKillFlag)
|
||||
{
|
||||
if (pOutputFilename == NULL)
|
||||
return VerifyFile(pInputFilename, pPercentageDone, ProgressCallback, pKillFlag);
|
||||
else
|
||||
return DecompressCore(pInputFilename, pOutputFilename, UNMAC_DECODER_OUTPUT_WAV, -1, pPercentageDone, ProgressCallback, pKillFlag);
|
||||
}
|
||||
|
||||
/*****************************************************************************************
|
||||
Convert file
|
||||
*****************************************************************************************/
|
||||
int __stdcall ConvertFile(const char * pInputFilename, const char * pOutputFilename, int nCompressionLevel, int * pPercentageDone, APE_PROGRESS_CALLBACK ProgressCallback, int * pKillFlag)
|
||||
{
|
||||
return DecompressCore(pInputFilename, pOutputFilename, UNMAC_DECODER_OUTPUT_APE, nCompressionLevel, pPercentageDone, ProgressCallback, pKillFlag);
|
||||
}
|
||||
|
||||
/*****************************************************************************************
|
||||
Decompress a file using the specified output method
|
||||
*****************************************************************************************/
|
||||
int DecompressCore(const char * pInputFilename, const char * pOutputFilename, int nOutputMode, int nCompressionLevel, int * pPercentageDone, APE_PROGRESS_CALLBACK ProgressCallback, int * pKillFlag)
|
||||
{
|
||||
// error check the function parameters
|
||||
if ((pInputFilename == NULL) || (pPercentageDone == NULL) || (pKillFlag == NULL))
|
||||
{
|
||||
return ERROR_INVALID_FUNCTION_PARAMETER;
|
||||
}
|
||||
|
||||
// variable declares
|
||||
int nFunctionRetVal = ERROR_SUCCESS;
|
||||
CSmartPtr<IO_CLASS_NAME> spioOutput;
|
||||
CSmartPtr<IAPECompress> spAPECompress;
|
||||
CSmartPtr<IAPEDecompress> spAPEDecompress;
|
||||
CSmartPtr<unsigned char> spTempBuffer;
|
||||
CSmartPtr<CMACProgressHelper> spMACProgressHelper;
|
||||
WAVEFORMATEX wfeInput;
|
||||
|
||||
try
|
||||
{
|
||||
// create the decoder
|
||||
spAPEDecompress.Assign(CreateIAPEDecompress(pInputFilename, &nFunctionRetVal));
|
||||
if (spAPEDecompress == NULL || nFunctionRetVal != ERROR_SUCCESS) throw(nFunctionRetVal);
|
||||
|
||||
// get the input format
|
||||
THROW_ON_ERROR(spAPEDecompress->GetInfo(APE_INFO_WAVEFORMATEX, (int) &wfeInput))
|
||||
|
||||
// allocate space for the header
|
||||
spTempBuffer.Assign(new unsigned char [spAPEDecompress->GetInfo(APE_INFO_WAV_HEADER_BYTES)], TRUE);
|
||||
if (spTempBuffer == NULL) throw(ERROR_INSUFFICIENT_MEMORY);
|
||||
|
||||
// get the header
|
||||
THROW_ON_ERROR(spAPEDecompress->GetInfo(APE_INFO_WAV_HEADER_DATA, (int) spTempBuffer.GetPtr(), spAPEDecompress->GetInfo(APE_INFO_WAV_HEADER_BYTES)));
|
||||
|
||||
// initialize the output
|
||||
if (nOutputMode == UNMAC_DECODER_OUTPUT_WAV)
|
||||
{
|
||||
// create the file
|
||||
spioOutput.Assign(new IO_CLASS_NAME); THROW_ON_ERROR(spioOutput->Create(pOutputFilename))
|
||||
|
||||
// output the header
|
||||
THROW_ON_ERROR(WriteSafe(spioOutput, spTempBuffer, spAPEDecompress->GetInfo(APE_INFO_WAV_HEADER_BYTES)));
|
||||
}
|
||||
else if (nOutputMode == UNMAC_DECODER_OUTPUT_APE)
|
||||
{
|
||||
// quit if there is nothing to do
|
||||
if (spAPEDecompress->GetInfo(APE_INFO_FILE_VERSION) == MAC_VERSION_NUMBER && spAPEDecompress->GetInfo(APE_INFO_COMPRESSION_LEVEL) == nCompressionLevel)
|
||||
throw(ERROR_SKIPPED);
|
||||
|
||||
// create and start the compressor
|
||||
spAPECompress.Assign(CreateIAPECompress());
|
||||
THROW_ON_ERROR(spAPECompress->Start(pOutputFilename, &wfeInput, spAPEDecompress->GetInfo(APE_DECOMPRESS_TOTAL_BLOCKS) * spAPEDecompress->GetInfo(APE_INFO_BLOCK_ALIGN),
|
||||
nCompressionLevel, spTempBuffer, spAPEDecompress->GetInfo(APE_INFO_WAV_HEADER_BYTES)))
|
||||
}
|
||||
|
||||
// allocate space for decompression
|
||||
spTempBuffer.Assign(new unsigned char [spAPEDecompress->GetInfo(APE_INFO_BLOCK_ALIGN) * BLOCKS_PER_DECODE], TRUE);
|
||||
if (spTempBuffer == NULL) throw(ERROR_INSUFFICIENT_MEMORY);
|
||||
|
||||
int nBlocksLeft = spAPEDecompress->GetInfo(APE_DECOMPRESS_TOTAL_BLOCKS);
|
||||
|
||||
// create the progress helper
|
||||
spMACProgressHelper.Assign(new CMACProgressHelper(nBlocksLeft / BLOCKS_PER_DECODE, pPercentageDone, ProgressCallback, pKillFlag));
|
||||
|
||||
// main decoding loop
|
||||
while (nBlocksLeft > 0)
|
||||
{
|
||||
// decode data
|
||||
int nBlocksDecoded = -1;
|
||||
int nRetVal = spAPEDecompress->GetData((char *) spTempBuffer.GetPtr(), BLOCKS_PER_DECODE, &nBlocksDecoded);
|
||||
if (nRetVal != ERROR_SUCCESS)
|
||||
throw(ERROR_INVALID_CHECKSUM);
|
||||
|
||||
// handle the output
|
||||
if (nOutputMode == UNMAC_DECODER_OUTPUT_WAV)
|
||||
{
|
||||
unsigned int nBytesToWrite = (nBlocksDecoded * spAPEDecompress->GetInfo(APE_INFO_BLOCK_ALIGN));
|
||||
unsigned int nBytesWritten = 0;
|
||||
int nRetVal = spioOutput->Write(spTempBuffer, nBytesToWrite, &nBytesWritten);
|
||||
if ((nRetVal != 0) || (nBytesToWrite != nBytesWritten))
|
||||
throw(ERROR_IO_WRITE);
|
||||
}
|
||||
else if (nOutputMode == UNMAC_DECODER_OUTPUT_APE)
|
||||
{
|
||||
THROW_ON_ERROR(spAPECompress->AddData(spTempBuffer, nBlocksDecoded * spAPEDecompress->GetInfo(APE_INFO_BLOCK_ALIGN)))
|
||||
}
|
||||
|
||||
// update amount remaining
|
||||
nBlocksLeft -= nBlocksDecoded;
|
||||
|
||||
// update progress and kill flag
|
||||
spMACProgressHelper->UpdateProgress();
|
||||
if (spMACProgressHelper->ProcessKillFlag(TRUE) != 0)
|
||||
throw(ERROR_USER_STOPPED_PROCESSING);
|
||||
}
|
||||
|
||||
// terminate the output
|
||||
if (nOutputMode == UNMAC_DECODER_OUTPUT_WAV)
|
||||
{
|
||||
// write any terminating WAV data
|
||||
if (spAPEDecompress->GetInfo(APE_INFO_WAV_TERMINATING_BYTES) > 0)
|
||||
{
|
||||
spTempBuffer.Assign(new unsigned char[spAPEDecompress->GetInfo(APE_INFO_WAV_TERMINATING_BYTES)], TRUE);
|
||||
if (spTempBuffer == NULL) throw(ERROR_INSUFFICIENT_MEMORY);
|
||||
THROW_ON_ERROR(spAPEDecompress->GetInfo(APE_INFO_WAV_TERMINATING_DATA, (int) spTempBuffer.GetPtr(), spAPEDecompress->GetInfo(APE_INFO_WAV_TERMINATING_BYTES)))
|
||||
|
||||
unsigned int nBytesToWrite = spAPEDecompress->GetInfo(APE_INFO_WAV_TERMINATING_BYTES);
|
||||
unsigned int nBytesWritten = 0;
|
||||
int nRetVal = spioOutput->Write(spTempBuffer, nBytesToWrite, &nBytesWritten);
|
||||
if ((nRetVal != 0) || (nBytesToWrite != nBytesWritten))
|
||||
throw(ERROR_IO_WRITE);
|
||||
}
|
||||
}
|
||||
else if (nOutputMode == UNMAC_DECODER_OUTPUT_APE)
|
||||
{
|
||||
// write the WAV data and any tag
|
||||
int nTagBytes = GET_TAG(spAPEDecompress)->GetTagBytes();
|
||||
BOOL bHasTag = (nTagBytes > 0);
|
||||
int nTerminatingBytes = nTagBytes;
|
||||
nTerminatingBytes += spAPEDecompress->GetInfo(APE_INFO_WAV_TERMINATING_BYTES);
|
||||
|
||||
if (nTerminatingBytes > 0)
|
||||
{
|
||||
spTempBuffer.Assign(new unsigned char[nTerminatingBytes], TRUE);
|
||||
if (spTempBuffer == NULL) throw(ERROR_INSUFFICIENT_MEMORY);
|
||||
|
||||
THROW_ON_ERROR(spAPEDecompress->GetInfo(APE_INFO_WAV_TERMINATING_DATA, (int) spTempBuffer.GetPtr(), nTerminatingBytes))
|
||||
|
||||
if (bHasTag)
|
||||
{
|
||||
unsigned int nBytesRead = 0;
|
||||
THROW_ON_ERROR(GET_IO(spAPEDecompress)->Seek(-(nTagBytes), FILE_END))
|
||||
THROW_ON_ERROR(GET_IO(spAPEDecompress)->Read(&spTempBuffer[spAPEDecompress->GetInfo(APE_INFO_WAV_TERMINATING_BYTES)], nTagBytes, &nBytesRead))
|
||||
}
|
||||
|
||||
THROW_ON_ERROR(spAPECompress->Finish(spTempBuffer, nTerminatingBytes, spAPEDecompress->GetInfo(APE_INFO_WAV_TERMINATING_BYTES)));
|
||||
}
|
||||
else
|
||||
{
|
||||
THROW_ON_ERROR(spAPECompress->Finish(NULL, 0, 0));
|
||||
}
|
||||
}
|
||||
|
||||
// fire the "complete" progress notification
|
||||
spMACProgressHelper->UpdateProgressComplete();
|
||||
}
|
||||
catch(int nErrorCode)
|
||||
{
|
||||
nFunctionRetVal = (nErrorCode == 0) ? ERROR_UNDEFINED : nErrorCode;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
nFunctionRetVal = ERROR_UNDEFINED;
|
||||
}
|
||||
|
||||
// return
|
||||
return nFunctionRetVal;
|
||||
}
|
544
gst/monkeyaudio/libmonkeyaudio/APETag.cpp
Normal file
544
gst/monkeyaudio/libmonkeyaudio/APETag.cpp
Normal file
|
@ -0,0 +1,544 @@
|
|||
#include "All.h"
|
||||
#include "ID3Genres.h"
|
||||
#include "APETag.h"
|
||||
#include IO_HEADER_FILE
|
||||
|
||||
CAPETagField::CAPETagField(const char * pFieldName, const char * pFieldValue, int nFieldBytes, int nFlags)
|
||||
{
|
||||
m_nFieldNameBytes = strlen(pFieldName) + 1;
|
||||
m_spFieldName.Assign(new char [m_nFieldNameBytes], TRUE);
|
||||
strcpy(m_spFieldName, pFieldName);
|
||||
|
||||
if (nFieldBytes == -1)
|
||||
{
|
||||
m_nFieldValueBytes = strlen(pFieldValue) + 1;
|
||||
m_spFieldValue.Assign(new char [m_nFieldValueBytes], TRUE);
|
||||
|
||||
strcpy(m_spFieldValue, pFieldValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_nFieldValueBytes = nFieldBytes;
|
||||
m_spFieldValue.Assign(new char [m_nFieldValueBytes], TRUE);
|
||||
|
||||
memcpy(m_spFieldValue, pFieldValue, nFieldBytes);
|
||||
}
|
||||
|
||||
m_nFieldFlags = nFlags;
|
||||
}
|
||||
|
||||
CAPETagField::~CAPETagField()
|
||||
{
|
||||
}
|
||||
|
||||
int CAPETagField::GetFieldSize()
|
||||
{
|
||||
return (strlen(m_spFieldName) + 1) + m_nFieldValueBytes + 4 + 4;
|
||||
}
|
||||
|
||||
const char * CAPETagField::GetFieldName()
|
||||
{
|
||||
return m_spFieldName;
|
||||
}
|
||||
|
||||
const char * CAPETagField::GetFieldValue()
|
||||
{
|
||||
return m_spFieldValue;
|
||||
}
|
||||
|
||||
int CAPETagField::GetFieldValueSize()
|
||||
{
|
||||
return m_nFieldValueBytes;
|
||||
}
|
||||
|
||||
int CAPETagField::GetFieldFlags()
|
||||
{
|
||||
return m_nFieldFlags;
|
||||
}
|
||||
|
||||
int CAPETagField::SaveField(char * pBuffer)
|
||||
{
|
||||
*((int *) pBuffer) = m_nFieldValueBytes;
|
||||
pBuffer += 4;
|
||||
*((int *) pBuffer) = m_nFieldFlags;
|
||||
pBuffer += 4;
|
||||
strcpy(pBuffer, m_spFieldName);
|
||||
pBuffer += strlen(m_spFieldName) + 1;
|
||||
memcpy(pBuffer, m_spFieldValue, m_nFieldValueBytes);
|
||||
|
||||
return GetFieldSize();
|
||||
}
|
||||
|
||||
CAPETag::CAPETag(const char * pFilename, BOOL bAnalyze)
|
||||
{
|
||||
m_spIO.Assign(new IO_CLASS_NAME);
|
||||
m_spIO->Open(pFilename);
|
||||
|
||||
m_bAnalyzed = FALSE;
|
||||
m_nFields = 0;
|
||||
m_nTagBytes = 0;
|
||||
m_nRetrieveFieldIndex = 0;
|
||||
|
||||
if (bAnalyze)
|
||||
{
|
||||
Analyze();
|
||||
}
|
||||
}
|
||||
|
||||
CAPETag::CAPETag(CIO * pIO, BOOL bAnalyze)
|
||||
{
|
||||
m_spIO.Assign(pIO, FALSE, FALSE); // we don't own the IO source
|
||||
m_bAnalyzed = FALSE;
|
||||
m_nFields = 0;
|
||||
m_nTagBytes = 0;
|
||||
m_nRetrieveFieldIndex = 0;
|
||||
|
||||
if (bAnalyze)
|
||||
{
|
||||
Analyze();
|
||||
}
|
||||
}
|
||||
|
||||
CAPETag::~CAPETag()
|
||||
{
|
||||
ClearFields();
|
||||
}
|
||||
|
||||
int CAPETag::GetTagBytes()
|
||||
{
|
||||
if (m_bAnalyzed == FALSE) { Analyze(); }
|
||||
|
||||
return m_nTagBytes;
|
||||
}
|
||||
|
||||
BOOL CAPETag::GetNextTagField(BOOL bFirst, CAPETagField ** ppAPETagField)
|
||||
{
|
||||
if (bFirst)
|
||||
m_nRetrieveFieldIndex = 0;
|
||||
|
||||
if (m_nRetrieveFieldIndex >= m_nFields)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
*ppAPETagField = m_aryFields[m_nRetrieveFieldIndex];
|
||||
m_nRetrieveFieldIndex++;
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
int CAPETag::Save(BOOL bUseOldID3)
|
||||
{
|
||||
if (Remove(FALSE) != 0)
|
||||
return -1;
|
||||
|
||||
if (m_nFields == 0) { return 0; }
|
||||
|
||||
int nRetVal = -1;
|
||||
|
||||
if (bUseOldID3 == FALSE)
|
||||
{
|
||||
int z; // loop variable
|
||||
int nTotalTagBytes = sizeof(APE_TAG_FOOTER);
|
||||
for (z = 0; z < m_nFields; z++)
|
||||
nTotalTagBytes += m_aryFields[z]->GetFieldSize();
|
||||
|
||||
CSmartPtr<char> spRawTag(new char [nTotalTagBytes], TRUE);
|
||||
|
||||
int nLocation = 0;
|
||||
for (z = 0; z < m_nFields; z++)
|
||||
nLocation += m_aryFields[z]->SaveField(&spRawTag[nLocation]);
|
||||
|
||||
APE_TAG_FOOTER APETagFooter;
|
||||
strncpy(APETagFooter.cID, "APETAGEX", 8);
|
||||
ZeroMemory(APETagFooter.cReserved, 8);
|
||||
APETagFooter.nFields = m_nFields;
|
||||
APETagFooter.nFlags = 0;
|
||||
APETagFooter.nSize = nTotalTagBytes;
|
||||
APETagFooter.nVersion = CURRENT_APE_TAG_VERSION;
|
||||
|
||||
memcpy(&spRawTag[nLocation], &APETagFooter, sizeof(APE_TAG_FOOTER));
|
||||
|
||||
nRetVal = WriteBufferToEndOfIO(spRawTag, nTotalTagBytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
// build the ID3 tag
|
||||
ID3_TAG ID3Tag;
|
||||
CreateID3Tag(&ID3Tag);
|
||||
nRetVal = WriteBufferToEndOfIO(&ID3Tag, sizeof(ID3_TAG));
|
||||
}
|
||||
|
||||
return nRetVal;
|
||||
}
|
||||
|
||||
int CAPETag::WriteBufferToEndOfIO(void * pBuffer, int nBytes)
|
||||
{
|
||||
int nOriginalPosition = m_spIO->GetPosition();
|
||||
|
||||
unsigned int nBytesWritten = 0;
|
||||
m_spIO->Seek(0, FILE_END);
|
||||
|
||||
int nRetVal = m_spIO->Write(pBuffer, nBytes, &nBytesWritten);
|
||||
|
||||
m_spIO->Seek(nOriginalPosition, FILE_BEGIN);
|
||||
|
||||
return nRetVal;
|
||||
}
|
||||
|
||||
int CAPETag::Analyze()
|
||||
{
|
||||
// clean-up
|
||||
ID3_TAG ID3Tag;
|
||||
ClearFields();
|
||||
m_nTagBytes = 0;
|
||||
|
||||
m_bAnalyzed = TRUE;
|
||||
|
||||
// store the original location
|
||||
int nOriginalPosition = m_spIO->GetPosition();
|
||||
|
||||
// check for a tag
|
||||
unsigned int nBytesRead;
|
||||
int nRetVal;
|
||||
m_bHasID3Tag = FALSE;
|
||||
m_bHasAPETag = FALSE;
|
||||
m_spIO->Seek(-ID3_TAG_BYTES, FILE_END);
|
||||
nRetVal = m_spIO->Read((unsigned char *) &ID3Tag, sizeof(ID3_TAG), &nBytesRead);
|
||||
|
||||
if ((nBytesRead == sizeof(ID3_TAG)) && (nRetVal == 0))
|
||||
{
|
||||
if (ID3Tag.TagHeader[0] == 'T' && ID3Tag.TagHeader[1] == 'A' && ID3Tag.TagHeader[2] == 'G')
|
||||
{
|
||||
m_bHasID3Tag = TRUE;
|
||||
m_nTagBytes += ID3_TAG_BYTES;
|
||||
}
|
||||
}
|
||||
|
||||
// set the fields
|
||||
if (m_bHasID3Tag)
|
||||
{
|
||||
SetFieldID3String(APE_TAG_FIELD_ARTIST, ID3Tag.Artist, 30);
|
||||
SetFieldID3String(APE_TAG_FIELD_ALBUM, ID3Tag.Album, 30);
|
||||
SetFieldID3String(APE_TAG_FIELD_TITLE, ID3Tag.Title, 30);
|
||||
SetFieldID3String(APE_TAG_FIELD_COMMENT, ID3Tag.Comment, 28);
|
||||
SetFieldID3String(APE_TAG_FIELD_YEAR, ID3Tag.Year, 4);
|
||||
|
||||
char cTemp[16]; sprintf(cTemp, "%d", ID3Tag.Track);
|
||||
SetField(APE_TAG_FIELD_TRACK, cTemp);
|
||||
|
||||
if ((ID3Tag.Genre == GENRE_UNDEFINED) || (ID3Tag.Genre >= GENRE_COUNT))
|
||||
SetField(APE_TAG_FIELD_GENRE, APE_TAG_GENRE_UNDEFINED);
|
||||
else
|
||||
SetField(APE_TAG_FIELD_GENRE, (char *) g_ID3Genre[ID3Tag.Genre]);
|
||||
}
|
||||
|
||||
// try loading the APE tag
|
||||
if (m_bHasID3Tag == FALSE)
|
||||
{
|
||||
APE_TAG_FOOTER APETagFooter;
|
||||
m_spIO->Seek(-int(sizeof(APE_TAG_FOOTER)), FILE_END);
|
||||
nRetVal = m_spIO->Read((unsigned char *) &APETagFooter, sizeof(APE_TAG_FOOTER), &nBytesRead);
|
||||
if ((nBytesRead == sizeof(APE_TAG_FOOTER)) && (nRetVal == 0))
|
||||
{
|
||||
if ((strncmp(APETagFooter.cID, "APETAGEX", 8) == 0) &&
|
||||
(APETagFooter.nVersion <= CURRENT_APE_TAG_VERSION) &&
|
||||
(APETagFooter.nFields <= 65536) &&
|
||||
(APETagFooter.nSize <= (1024 * 1024 * 16)))
|
||||
{
|
||||
m_bHasAPETag = TRUE;
|
||||
|
||||
int nRawFieldBytes = APETagFooter.nSize - sizeof(APE_TAG_FOOTER);
|
||||
m_nTagBytes += APETagFooter.nSize;
|
||||
|
||||
char * pRawTag = new char [nRawFieldBytes];
|
||||
|
||||
m_spIO->Seek(-APETagFooter.nSize, FILE_END);
|
||||
nRetVal = m_spIO->Read((unsigned char *) pRawTag, nRawFieldBytes, &nBytesRead);
|
||||
if ((nRetVal == 0) && (nRawFieldBytes == int(nBytesRead)))
|
||||
{
|
||||
// parse out the raw fields
|
||||
int nLocation = 0;
|
||||
|
||||
for (int z = 0; z < APETagFooter.nFields; z++)
|
||||
{
|
||||
int nFieldValueSize = *((int *) &pRawTag[nLocation]);
|
||||
nLocation += 4;
|
||||
int nFieldFlags = *((int *) &pRawTag[nLocation]);
|
||||
nLocation += 4;
|
||||
|
||||
char cNameBuffer[256];
|
||||
strcpy(cNameBuffer, &pRawTag[nLocation]);
|
||||
nLocation += strlen(cNameBuffer) + 1;
|
||||
|
||||
char * pFieldBuffer = new char [nFieldValueSize];
|
||||
memcpy(pFieldBuffer, &pRawTag[nLocation], nFieldValueSize);
|
||||
nLocation += nFieldValueSize;
|
||||
|
||||
SetField(cNameBuffer, pFieldBuffer, nFieldValueSize, nFieldFlags);
|
||||
|
||||
delete [] pFieldBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
delete [] pRawTag;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// restore the file pointer
|
||||
m_spIO->Seek(nOriginalPosition, FILE_BEGIN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CAPETag::ClearFields()
|
||||
{
|
||||
for (int z = 0; z < m_nFields; z++)
|
||||
{
|
||||
SAFE_DELETE(m_aryFields[z])
|
||||
}
|
||||
|
||||
m_nFields = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
CAPETagField * CAPETag::GetTagField(const char * pFieldName)
|
||||
{
|
||||
if (m_bAnalyzed == FALSE) { Analyze(); }
|
||||
|
||||
for (int z = 0; z < m_nFields; z++)
|
||||
{
|
||||
if (strcmp(m_aryFields[z]->GetFieldName(), pFieldName) == 0)
|
||||
return m_aryFields[z];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int CAPETag::GetField(const char * pFieldName, char * pBuffer, int * pBufferBytes)
|
||||
{
|
||||
if (m_bAnalyzed == FALSE) { Analyze(); }
|
||||
|
||||
CAPETagField * pAPETagField = GetTagField(pFieldName);
|
||||
if (pAPETagField == NULL)
|
||||
{
|
||||
strcpy(pBuffer, "");
|
||||
*pBufferBytes = 0;
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
int nFieldValueLength = strlen(pAPETagField->GetFieldValue());
|
||||
if (nFieldValueLength > *pBufferBytes)
|
||||
{
|
||||
memcpy(pBuffer, pAPETagField->GetFieldValue(), *pBufferBytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
*pBufferBytes = nFieldValueLength;
|
||||
strcpy(pBuffer, pAPETagField->GetFieldValue());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int CAPETag::CreateID3Tag(ID3_TAG * pID3Tag)
|
||||
{
|
||||
if (pID3Tag == NULL) { return -1; }
|
||||
if (m_bAnalyzed == FALSE) { Analyze(); }
|
||||
|
||||
if (m_nFields == 0) { return -1; }
|
||||
|
||||
ZeroMemory(pID3Tag, ID3_TAG_BYTES);
|
||||
|
||||
pID3Tag->TagHeader[0] = 'T';
|
||||
pID3Tag->TagHeader[1] = 'A';
|
||||
pID3Tag->TagHeader[2] = 'G';
|
||||
|
||||
GetFieldID3String(APE_TAG_FIELD_ARTIST, pID3Tag->Artist, 30);
|
||||
GetFieldID3String(APE_TAG_FIELD_ALBUM, pID3Tag->Album, 30);
|
||||
GetFieldID3String(APE_TAG_FIELD_TITLE, pID3Tag->Title, 30);
|
||||
GetFieldID3String(APE_TAG_FIELD_COMMENT, pID3Tag->Comment, 28);
|
||||
GetFieldID3String(APE_TAG_FIELD_YEAR, pID3Tag->Year, 4);
|
||||
|
||||
char cBuffer[256];
|
||||
int nBufferBytes;
|
||||
|
||||
nBufferBytes = 256;
|
||||
GetField("Track", cBuffer, &nBufferBytes);
|
||||
pID3Tag->Track = (unsigned char) atoi(cBuffer);
|
||||
|
||||
nBufferBytes = 256;
|
||||
GetField("Genre", cBuffer, &nBufferBytes);
|
||||
|
||||
pID3Tag->Genre = 255;
|
||||
|
||||
int nGenreIndex = 0;
|
||||
BOOL bFound = FALSE;
|
||||
while ((nGenreIndex < GENRE_COUNT) && (bFound == FALSE))
|
||||
{
|
||||
if (_stricmp(cBuffer, g_ID3Genre[nGenreIndex]) == 0)
|
||||
{
|
||||
pID3Tag->Genre = nGenreIndex;
|
||||
bFound = TRUE;
|
||||
}
|
||||
|
||||
nGenreIndex++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CAPETag::SetField(const char * pFieldName, const char * pFieldValue, int nFieldBytes, int nFlags)
|
||||
{
|
||||
if (m_bAnalyzed == FALSE) { Analyze(); }
|
||||
|
||||
if (pFieldName == NULL)
|
||||
return -1;
|
||||
|
||||
// get the right index
|
||||
int z = 0;
|
||||
while (z < m_nFields)
|
||||
{
|
||||
if (strcmp(m_aryFields[z]->GetFieldName(), pFieldName) == 0)
|
||||
break;
|
||||
|
||||
z++;
|
||||
}
|
||||
|
||||
BOOL bNewField = TRUE;
|
||||
if (z != m_nFields)
|
||||
{
|
||||
SAFE_DELETE(m_aryFields[z])
|
||||
bNewField = FALSE;
|
||||
}
|
||||
|
||||
if (nFieldBytes == -1)
|
||||
{
|
||||
if (pFieldValue == NULL || strlen(pFieldValue) == 0)
|
||||
{
|
||||
// shuffle down if necessary
|
||||
if (bNewField == FALSE)
|
||||
{
|
||||
memmove(&m_aryFields[z], &m_aryFields[z + 1], (256 - z - 1) * sizeof(CAPETagField *));
|
||||
m_nFields--;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (bNewField)
|
||||
m_nFields++;
|
||||
|
||||
m_aryFields[z] = new CAPETagField(pFieldName, (char *) pFieldValue, nFieldBytes, nFlags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CAPETag::Remove(BOOL bUpdate)
|
||||
{
|
||||
// variables
|
||||
unsigned int nBytesRead = 0;
|
||||
int nRetVal = 0;
|
||||
int nOriginalPosition = m_spIO->GetPosition();
|
||||
|
||||
BOOL bID3Removed = TRUE;
|
||||
BOOL bAPETagRemoved = TRUE;
|
||||
|
||||
BOOL bFailedToRemove = FALSE;
|
||||
|
||||
while (bID3Removed || bAPETagRemoved)
|
||||
{
|
||||
bID3Removed = FALSE;
|
||||
bAPETagRemoved = FALSE;
|
||||
|
||||
// ID3 tag
|
||||
if (m_spIO->GetSize() > ID3_TAG_BYTES)
|
||||
{
|
||||
char cTagHeader[3];
|
||||
m_spIO->Seek(-ID3_TAG_BYTES, FILE_END);
|
||||
nRetVal = m_spIO->Read(cTagHeader, 3, &nBytesRead);
|
||||
if ((nRetVal == 0) && (nBytesRead == 3))
|
||||
{
|
||||
if (strncmp(cTagHeader, "TAG", 3) == 0)
|
||||
{
|
||||
m_spIO->Seek(-ID3_TAG_BYTES, FILE_END);
|
||||
if (m_spIO->SetEOF() != 0)
|
||||
bFailedToRemove = TRUE;
|
||||
else
|
||||
bID3Removed = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// APE Tag
|
||||
if (m_spIO->GetSize() > sizeof(APE_TAG_FOOTER) && bFailedToRemove == FALSE)
|
||||
{
|
||||
APE_TAG_FOOTER APETagFooter;
|
||||
m_spIO->Seek(-int(sizeof(APE_TAG_FOOTER)), FILE_END);
|
||||
nRetVal = m_spIO->Read(&APETagFooter, sizeof(APE_TAG_FOOTER), &nBytesRead);
|
||||
if ((nRetVal == 0) && (nBytesRead == sizeof(APE_TAG_FOOTER)))
|
||||
{
|
||||
if ((strncmp(APETagFooter.cID, "APETAGEX", 8) == 0) &&
|
||||
(APETagFooter.nVersion <= CURRENT_APE_TAG_VERSION) &&
|
||||
(APETagFooter.nFields <= 65536) &&
|
||||
(APETagFooter.nSize <= (1024 * 1024 * 16)))
|
||||
{
|
||||
m_spIO->Seek(-APETagFooter.nSize, FILE_END);
|
||||
if (m_spIO->SetEOF() != 0)
|
||||
bFailedToRemove = TRUE;
|
||||
else
|
||||
bAPETagRemoved = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
m_spIO->Seek(nOriginalPosition, FILE_BEGIN);
|
||||
|
||||
if (bUpdate && bFailedToRemove == FALSE)
|
||||
{
|
||||
Analyze();
|
||||
}
|
||||
|
||||
return bFailedToRemove ? -1 : 0;
|
||||
}
|
||||
|
||||
int CAPETag::SetFieldID3String(const char * pFieldName, const char * pFieldValue, int nBytes)
|
||||
{
|
||||
// allocate a buffer and terminate it
|
||||
char * pBuffer = new char [nBytes + 1];
|
||||
pBuffer[nBytes] = 0;
|
||||
|
||||
// make a capped copy of the string
|
||||
memcpy(pBuffer, pFieldValue, nBytes);
|
||||
|
||||
// remove trailing white-space
|
||||
char * pEnd = &pBuffer[nBytes];
|
||||
while (((*pEnd == ' ') || (*pEnd == 0)) && pEnd >= &pBuffer[0]) { *pEnd-- = 0; }
|
||||
|
||||
// set the field
|
||||
SetField(pFieldName, pBuffer, -1, 0);
|
||||
|
||||
// clean-up
|
||||
delete [] pBuffer;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CAPETag::GetFieldID3String(const char * pFieldName, char * pBuffer, int nBytes)
|
||||
{
|
||||
int nBufferBytes = 256;
|
||||
char cField[256]; ZeroMemory(cField, 256);
|
||||
GetField(pFieldName, cField, &nBufferBytes);
|
||||
memcpy(pBuffer, cField, nBytes);
|
||||
|
||||
return 0;
|
||||
}
|
187
gst/monkeyaudio/libmonkeyaudio/APETag.h
Normal file
187
gst/monkeyaudio/libmonkeyaudio/APETag.h
Normal file
|
@ -0,0 +1,187 @@
|
|||
#ifndef APE_APETAG_H
|
||||
#define APE_APETAG_H
|
||||
|
||||
#include "IO.h"
|
||||
|
||||
/*****************************************************************************************
|
||||
Notes:
|
||||
|
||||
-When saving images, store the filename (no directory) (i.e. Cover.jpg) followed by
|
||||
a null terminator, followed by the image data.
|
||||
*****************************************************************************************/
|
||||
|
||||
/*****************************************************************************************
|
||||
The version of the APE tag
|
||||
*****************************************************************************************/
|
||||
#define CURRENT_APE_TAG_VERSION 1000
|
||||
|
||||
/*****************************************************************************************
|
||||
"Standard" APE tag fields
|
||||
*****************************************************************************************/
|
||||
#define APE_TAG_FIELD_TITLE "Title"
|
||||
#define APE_TAG_FIELD_ARTIST "Artist"
|
||||
#define APE_TAG_FIELD_ALBUM "Album"
|
||||
#define APE_TAG_FIELD_COMMENT "Comment"
|
||||
#define APE_TAG_FIELD_YEAR "Year"
|
||||
#define APE_TAG_FIELD_TRACK "Track"
|
||||
#define APE_TAG_FIELD_GENRE "Genre"
|
||||
#define APE_TAG_FIELD_COVER_ART_FRONT "Cover Art (front)"
|
||||
#define APE_TAG_FIELD_NOTES "Notes"
|
||||
#define APE_TAG_FIELD_LYRICS "Lyrics"
|
||||
#define APE_TAG_FIELD_COPYRIGHT "Copyright"
|
||||
#define APE_TAG_FIELD_BUY_URL "Buy URL"
|
||||
#define APE_TAG_FIELD_ARTIST_URL "Artist URL"
|
||||
#define APE_TAG_FIELD_PUBLISHER_URL "Publisher URL"
|
||||
#define APE_TAG_FIELD_FILE_URL "File URL"
|
||||
#define APE_TAG_FIELD_COPYRIGHT_URL "Copyright URL"
|
||||
#define APE_TAG_FIELD_MJ_METADATA "Media Jukebox Metadata"
|
||||
|
||||
/*****************************************************************************************
|
||||
Standard APE tag field values
|
||||
*****************************************************************************************/
|
||||
#define APE_TAG_GENRE_UNDEFINED "Undefined"
|
||||
|
||||
/*****************************************************************************************
|
||||
ID3 v1.1 tag
|
||||
*****************************************************************************************/
|
||||
#define ID3_TAG_BYTES 128
|
||||
struct ID3_TAG
|
||||
{
|
||||
char TagHeader[3]; // should equal 'TAG'
|
||||
char Title[30]; // title
|
||||
char Artist[30]; // artist
|
||||
char Album[30]; // album
|
||||
char Year[4]; // year
|
||||
char Comment[29]; // comment
|
||||
unsigned char Track; // track
|
||||
unsigned char Genre; // genre
|
||||
};
|
||||
|
||||
/*****************************************************************************************
|
||||
The footer at the end of APE tagged files
|
||||
*****************************************************************************************/
|
||||
struct APE_TAG_FOOTER
|
||||
{
|
||||
char cID[8]; // should equal 'APETAGEX'
|
||||
int nVersion; // equals CURRENT_APE_TAG_VERSION
|
||||
int nSize; // the complete size of the tag, including this footer
|
||||
int nFields; // the number of fields in the tag
|
||||
int nFlags; // the tag flags (none currently defined)
|
||||
char cReserved[8]; // reserved for later use
|
||||
};
|
||||
|
||||
/*****************************************************************************************
|
||||
CAPETagField class (an APE tag is an array of these)
|
||||
*****************************************************************************************/
|
||||
class CAPETagField
|
||||
{
|
||||
public:
|
||||
|
||||
// create a tag field (use nFieldBytes = -1 for null-terminated strings)
|
||||
CAPETagField(const char * pFieldName, const char * pFieldValue, int nFieldBytes = -1, int nFlags = 0);
|
||||
|
||||
// destructor
|
||||
~CAPETagField();
|
||||
|
||||
// gets the size of the entire field in bytes (name, value, and metadata)
|
||||
int GetFieldSize();
|
||||
|
||||
// get the name of the field
|
||||
const char * GetFieldName();
|
||||
|
||||
// get the value of the field
|
||||
const char * GetFieldValue();
|
||||
|
||||
// get the size of the value (in bytes)
|
||||
int GetFieldValueSize();
|
||||
|
||||
// get any special flags (none defined yet)
|
||||
int GetFieldFlags();
|
||||
|
||||
// output the entire field to a buffer (GetFieldSize() bytes)
|
||||
int SaveField(char * pBuffer);
|
||||
|
||||
private:
|
||||
|
||||
CSmartPtr<char> m_spFieldName;
|
||||
CSmartPtr<char> m_spFieldValue;
|
||||
int m_nFieldFlags;
|
||||
|
||||
int m_nFieldNameBytes;
|
||||
int m_nFieldValueBytes;
|
||||
};
|
||||
|
||||
/*****************************************************************************************
|
||||
CAPETag class
|
||||
*****************************************************************************************/
|
||||
class CAPETag
|
||||
{
|
||||
public:
|
||||
|
||||
// create an APE tag
|
||||
// bAnalyze determines whether it will analyze immediately or on the first request
|
||||
// be careful with multiple threads / file pointer movement if you don't analyze immediately
|
||||
CAPETag(CIO * pIO, BOOL bAnalyze = TRUE);
|
||||
CAPETag(const char * pFilename, BOOL bAnalyze = TRUE);
|
||||
|
||||
// destructor
|
||||
~CAPETag();
|
||||
|
||||
// save the tag to the I/O source (bUseOldID3 forces it to save as an ID3v1.1 tag instead of an APE tag)
|
||||
int Save(BOOL bUseOldID3 = FALSE);
|
||||
|
||||
// removes any tags from the file (bUpdate determines whether is should re-analyze after removing the tag)
|
||||
int Remove(BOOL bUpdate = TRUE);
|
||||
|
||||
// sets the value of a field (use nFieldBytes = -1 for null terminated strings)
|
||||
// note: to remove a field, call (ex. SetField(APE_TAG_FIELD_TITLE, NULL);)
|
||||
int SetField(const char * pFieldName, const char * pFieldValue, int nFieldBytes = -1, int nFlags = 0);
|
||||
|
||||
// gets the value of a field (returns -1 and an empty buffer if the field doesn't exist)
|
||||
int GetField(const char * pFieldName, char * pBuffer, int * pBufferBytes);
|
||||
|
||||
// clear all the fields
|
||||
int ClearFields();
|
||||
|
||||
// get the total tag bytes in the file from the last analyze
|
||||
// need to call Save() then Analyze() to update any changes
|
||||
int GetTagBytes();
|
||||
|
||||
// fills in an ID3_TAG using the current fields (useful for quickly converting the tag)
|
||||
int CreateID3Tag(ID3_TAG * pID3Tag);
|
||||
|
||||
// see whether the file has an ID3 or APE tag
|
||||
BOOL GetHasID3Tag() { if (m_bAnalyzed == FALSE) { Analyze(); } return m_bHasID3Tag; }
|
||||
BOOL GetHasAPETag() { if (m_bAnalyzed == FALSE) { Analyze(); } return m_bHasAPETag; }
|
||||
|
||||
// iterate through the tag fields
|
||||
// set bFirst to TRUE on the first call, and to FALSE on subsequent calls (TRUE resets the internal counter)
|
||||
// also, be careful since you're getting a pointer to the field in the tag (pointer expiration, etc.)
|
||||
BOOL GetNextTagField(BOOL bFirst, CAPETagField ** ppAPETagField);
|
||||
|
||||
// gets a desired tag field (returns NULL if not found)
|
||||
// again, be careful, because this a pointer to the actual field in this class
|
||||
CAPETagField * GetTagField(const char * pFieldName);
|
||||
|
||||
private:
|
||||
|
||||
// private functions
|
||||
int Analyze();
|
||||
int WriteBufferToEndOfIO(void * pBuffer, int nBytes);
|
||||
|
||||
// helper set / get field functions
|
||||
int SetFieldID3String(const char * pFieldName, const char * pFieldValue, int nBytes);
|
||||
int GetFieldID3String(const char * pFieldName, char * pBuffer, int nBytes);
|
||||
|
||||
// private data
|
||||
CSmartPtr<CIO> m_spIO;
|
||||
BOOL m_bAnalyzed;
|
||||
int m_nTagBytes;
|
||||
int m_nFields;
|
||||
CAPETagField * m_aryFields[256];
|
||||
BOOL m_bHasAPETag;
|
||||
BOOL m_bHasID3Tag;
|
||||
int m_nRetrieveFieldIndex;
|
||||
};
|
||||
|
||||
#endif /* APE_APETAG_H */
|
211
gst/monkeyaudio/libmonkeyaudio/All.h
Normal file
211
gst/monkeyaudio/libmonkeyaudio/All.h
Normal file
|
@ -0,0 +1,211 @@
|
|||
#ifndef APE_ALL_H
|
||||
#define APE_ALL_H
|
||||
|
||||
/*****************************************************************************************
|
||||
Global includes
|
||||
*****************************************************************************************/
|
||||
|
||||
#if defined _WIN32
|
||||
# include <windows.h>
|
||||
# include <mmsystem.h>
|
||||
#else
|
||||
# include <unistd.h>
|
||||
# include <time.h>
|
||||
# include <sys/time.h>
|
||||
# include <sys/types.h>
|
||||
# include <sys/stat.h>
|
||||
# include "NoWindows.h"
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <memory.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include "SmartPtr.h"
|
||||
|
||||
/*****************************************************************************************
|
||||
Global compiler settings (useful for porting)
|
||||
*****************************************************************************************/
|
||||
|
||||
#if defined _WIN32
|
||||
# define BACKWARDS_COMPATIBILITY
|
||||
# define ENABLE_ASSEMBLY
|
||||
#endif
|
||||
|
||||
#if defined BACKWARDS_COMPATIBILITY && !defined ENABLE_ASSEMBLY
|
||||
# error "Monkey's Audio requires assembly for backwards compatibility."
|
||||
#endif
|
||||
|
||||
#define ENABLE_COMPRESSION_MODE_FAST
|
||||
#define ENABLE_COMPRESSION_MODE_NORMAL
|
||||
#define ENABLE_COMPRESSION_MODE_HIGH
|
||||
#define ENABLE_COMPRESSION_MODE_EXTRA_HIGH
|
||||
#define ENABLE_COMPRESSION_MODE_INSANE_HIGH
|
||||
|
||||
#ifdef _WIN32
|
||||
# define IO_USE_WIN_FILE_IO
|
||||
# define IO_HEADER_FILE "WinFileIO.h"
|
||||
# define IO_CLASS_NAME CWinFileIO
|
||||
# define DLLEXPORT __declspec( dllexport )
|
||||
# define SLEEP(Milliseconds) ::Sleep(Milliseconds)
|
||||
# define MESSAGEBOX(PARENT, TEXT, CAPTION, TYPE) MessageBox(PARENT, TEXT, CAPTION, TYPE)
|
||||
# define PUMP_MESSAGE_LOOP { MSG Msg; while (PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE) != 0) { TranslateMessage(&Msg); DispatchMessage(&Msg); } }
|
||||
# define ODS OutputDebugString
|
||||
# define TICK_COUNT_TYPE unsigned long
|
||||
# define TICK_COUNT_READ(dst) dst = GetTickCount ()
|
||||
# define TICK_COUNT_FREQ 1000
|
||||
#else
|
||||
# define IO_USE_STD_LIB_FILE_IO
|
||||
# define IO_HEADER_FILE "StdLibFileIO.h"
|
||||
# define IO_CLASS_NAME CStdLibFileIO
|
||||
# define DLLEXPORT
|
||||
# define SLEEP(Milliseconds) { struct timespec t; t.tv_sec = (Milliseconds)/1000; t.tv_nsec=(Milliseconds)%1000*1000000; nanosleep (&t, NULL); }
|
||||
# define MESSAGEBOX(PARENT, TEXT, CAPTION, TYPE)
|
||||
# define PUMP_MESSAGE_LOOP
|
||||
# define ODS printf
|
||||
# if 0
|
||||
# define TICK_COUNT_TYPE unsigned long
|
||||
# define TICK_COUNT_READ(dst) dst = time (NULL))
|
||||
# define TICK_COUNT_FREQ 1
|
||||
# else
|
||||
# define TICK_COUNT_TYPE unsigned long long
|
||||
# define TICK_COUNT_READ(dst) { struct timeval t; gettimeofday ( &t, NULL ); dst = t.tv_sec * 1000000LLU + t.tv_usec; }
|
||||
# define TICK_COUNT_FREQ 1000000
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*****************************************************************************************
|
||||
Global Defines
|
||||
*****************************************************************************************/
|
||||
#define MAC_VERSION_NUMBER 3960
|
||||
#define MAC_VERSION_STRING "3.96b4"
|
||||
#define PLUGIN_NAME "Monkey's Audio Player "MAC_VERSION_STRING
|
||||
#define MJ_PLUGIN_NAME "APE Plugin (v"MAC_VERSION_STRING")"
|
||||
#define CONSOLE_NAME "--- Monkey's Audio Console Front End (v"MAC_VERSION_STRING") (c) Matthew T. Ashland ---\n"
|
||||
#define PLUGIN_ABOUT "Monkey's Audio Player v"MAC_VERSION_STRING"\nCopyrighted (c) 2000-2002 by Matthew T. Ashland"
|
||||
#define MAC_DLL_INTERFACE_VERSION_NUMBER 1000
|
||||
|
||||
/*****************************************************************************************
|
||||
Macros
|
||||
*****************************************************************************************/
|
||||
#define MB(TEST) MESSAGEBOX ( NULL, TEST, "Message...", MB_OK );
|
||||
#define MBN(NUMBER) { char cNumber[16]; ltoa(NUMBER, cNumber, 10); MESSAGEBOX(NULL, cNumber, "Message...", MB_OK); }
|
||||
|
||||
#define SAFE_DELETE(POINTER) if (POINTER) { delete POINTER; POINTER = NULL; }
|
||||
#define SAFE_ARRAY_DELETE(POINTER) if (POINTER) { delete [] POINTER; POINTER = NULL; }
|
||||
#define SAFE_VOID_CLASS_DELETE(POINTER, Class) { Class *pClass = (Class *) POINTER; if (pClass) { delete pClass; POINTER = NULL; } }
|
||||
#define SAFE_FILE_CLOSE(HANDLE) if (HANDLE != INVALID_HANDLE_VALUE) { CloseHandle(HANDLE); HANDLE = INVALID_HANDLE_VALUE; }
|
||||
|
||||
#define ODN(NUMBER) { char cNumber[16]; sprintf(cNumber, "%d\r\n", int(NUMBER)); ODS(cNumber); }
|
||||
|
||||
#define CATCH_ERRORS(CODE) try { CODE } catch(...) { }
|
||||
|
||||
#define RETURN_ON_ERROR(FUNCTION) { int nRetVal = FUNCTION; if (nRetVal != 0) { return nRetVal; } }
|
||||
#define RETURN_VALUE_ON_ERROR(FUNCTION, VALUE) { int nRetVal = FUNCTION; if (nRetVal != 0) { return VALUE; } }
|
||||
#define RETURN_ON_EXCEPTION(CODE, VALUE) { try { CODE } catch(...) { return VALUE; } }
|
||||
|
||||
#define THROW_ON_ERROR(CODE) { int nRetVal = CODE; if (nRetVal != 0) throw(nRetVal); }
|
||||
|
||||
#define EXPAND_1_TIMES(CODE) CODE
|
||||
#define EXPAND_2_TIMES(CODE) CODE CODE
|
||||
#define EXPAND_3_TIMES(CODE) CODE CODE CODE
|
||||
#define EXPAND_4_TIMES(CODE) CODE CODE CODE CODE
|
||||
#define EXPAND_5_TIMES(CODE) CODE CODE CODE CODE CODE
|
||||
#define EXPAND_6_TIMES(CODE) CODE CODE CODE CODE CODE CODE
|
||||
#define EXPAND_7_TIMES(CODE) CODE CODE CODE CODE CODE CODE CODE
|
||||
#define EXPAND_8_TIMES(CODE) CODE CODE CODE CODE CODE CODE CODE CODE
|
||||
#define EXPAND_12_TIMES(CODE) CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE
|
||||
#define EXPAND_14_TIMES(CODE) CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE
|
||||
#define EXPAND_15_TIMES(CODE) CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE
|
||||
#define EXPAND_16_TIMES(CODE) CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE
|
||||
#define EXPAND_30_TIMES(CODE) CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE
|
||||
#define EXPAND_31_TIMES(CODE) CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE
|
||||
#define EXPAND_32_TIMES(CODE) CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE
|
||||
#define EXPAND_64_TIMES(CODE) CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE CODE
|
||||
#define EXPAND_N_TIMES(NUMBER, CODE) EXPAND_##NUMBER##_TIMES(CODE)
|
||||
|
||||
#define UNROLL_4_TIMES(MACRO) MACRO(0) MACRO(1) MACRO(2) MACRO(3)
|
||||
#define UNROLL_8_TIMES(MACRO) MACRO(0) MACRO(1) MACRO(2) MACRO(3) MACRO(4) MACRO(5) MACRO(6) MACRO(7)
|
||||
#define UNROLL_15_TIMES(MACRO) MACRO(0) MACRO(1) MACRO(2) MACRO(3) MACRO(4) MACRO(5) MACRO(6) MACRO(7) MACRO(8) MACRO(9) MACRO(10) MACRO(11) MACRO(12) MACRO(13) MACRO(14)
|
||||
#define UNROLL_16_TIMES(MACRO) MACRO(0) MACRO(1) MACRO(2) MACRO(3) MACRO(4) MACRO(5) MACRO(6) MACRO(7) MACRO(8) MACRO(9) MACRO(10) MACRO(11) MACRO(12) MACRO(13) MACRO(14) MACRO(15)
|
||||
#define UNROLL_64_TIMES(MACRO) MACRO(0) MACRO(1) MACRO(2) MACRO(3) MACRO(4) MACRO(5) MACRO(6) MACRO(7) MACRO(8) MACRO(9) MACRO(10) MACRO(11) MACRO(12) MACRO(13) MACRO(14) MACRO(15) MACRO(16) MACRO(17) MACRO(18) MACRO(19) MACRO(20) MACRO(21) MACRO(22) MACRO(23) MACRO(24) MACRO(25) MACRO(26) MACRO(27) MACRO(28) MACRO(29) MACRO(30) MACRO(31) MACRO(32) MACRO(33) MACRO(34) MACRO(35) MACRO(36) MACRO(37) MACRO(38) MACRO(39) MACRO(40) MACRO(41) MACRO(42) MACRO(43) MACRO(44) MACRO(45) MACRO(46) MACRO(47) MACRO(48) MACRO(49) MACRO(50) MACRO(51) MACRO(52) MACRO(53) MACRO(54) MACRO(55) MACRO(56) MACRO(57) MACRO(58) MACRO(59) MACRO(60) MACRO(61) MACRO(62) MACRO(63)
|
||||
#define UNROLL_128_TIMES(MACRO) MACRO(0) MACRO(1) MACRO(2) MACRO(3) MACRO(4) MACRO(5) MACRO(6) MACRO(7) MACRO(8) MACRO(9) MACRO(10) MACRO(11) MACRO(12) MACRO(13) MACRO(14) MACRO(15) MACRO(16) MACRO(17) MACRO(18) MACRO(19) MACRO(20) MACRO(21) MACRO(22) MACRO(23) MACRO(24) MACRO(25) MACRO(26) MACRO(27) MACRO(28) MACRO(29) MACRO(30) MACRO(31) MACRO(32) MACRO(33) MACRO(34) MACRO(35) MACRO(36) MACRO(37) MACRO(38) MACRO(39) MACRO(40) MACRO(41) MACRO(42) MACRO(43) MACRO(44) MACRO(45) MACRO(46) MACRO(47) MACRO(48) MACRO(49) MACRO(50) MACRO(51) MACRO(52) MACRO(53) MACRO(54) MACRO(55) MACRO(56) MACRO(57) MACRO(58) MACRO(59) MACRO(60) MACRO(61) MACRO(62) MACRO(63) MACRO(64) MACRO(65) MACRO(66) MACRO(67) MACRO(68) MACRO(69) MACRO(70) MACRO(71) MACRO(72) MACRO(73) MACRO(74) MACRO(75) MACRO(76) MACRO(77) MACRO(78) MACRO(79) MACRO(80) MACRO(81) MACRO(82) MACRO(83) MACRO(84) MACRO(85) MACRO(86) MACRO(87) MACRO(88) MACRO(89) MACRO(90) MACRO(91) MACRO(92) MACRO(93) MACRO(94) MACRO(95) MACRO(96) MACRO(97) MACRO(98) MACRO(99) MACRO(100) MACRO(101) MACRO(102) MACRO(103) MACRO(104) MACRO(105) MACRO(106) MACRO(107) MACRO(108) MACRO(109) MACRO(110) MACRO(111) MACRO(112) MACRO(113) MACRO(114) MACRO(115) MACRO(116) MACRO(117) MACRO(118) MACRO(119) MACRO(120) MACRO(121) MACRO(122) MACRO(123) MACRO(124) MACRO(125) MACRO(126) MACRO(127)
|
||||
#define UNROLL_256_TIMES(MACRO) MACRO(0) MACRO(1) MACRO(2) MACRO(3) MACRO(4) MACRO(5) MACRO(6) MACRO(7) MACRO(8) MACRO(9) MACRO(10) MACRO(11) MACRO(12) MACRO(13) MACRO(14) MACRO(15) MACRO(16) MACRO(17) MACRO(18) MACRO(19) MACRO(20) MACRO(21) MACRO(22) MACRO(23) MACRO(24) MACRO(25) MACRO(26) MACRO(27) MACRO(28) MACRO(29) MACRO(30) MACRO(31) MACRO(32) MACRO(33) MACRO(34) MACRO(35) MACRO(36) MACRO(37) MACRO(38) MACRO(39) MACRO(40) MACRO(41) MACRO(42) MACRO(43) MACRO(44) MACRO(45) MACRO(46) MACRO(47) MACRO(48) MACRO(49) MACRO(50) MACRO(51) MACRO(52) MACRO(53) MACRO(54) MACRO(55) MACRO(56) MACRO(57) MACRO(58) MACRO(59) MACRO(60) MACRO(61) MACRO(62) MACRO(63) MACRO(64) MACRO(65) MACRO(66) MACRO(67) MACRO(68) MACRO(69) MACRO(70) MACRO(71) MACRO(72) MACRO(73) MACRO(74) MACRO(75) MACRO(76) MACRO(77) MACRO(78) MACRO(79) MACRO(80) MACRO(81) MACRO(82) MACRO(83) MACRO(84) MACRO(85) MACRO(86) MACRO(87) MACRO(88) MACRO(89) MACRO(90) MACRO(91) MACRO(92) MACRO(93) MACRO(94) MACRO(95) MACRO(96) MACRO(97) MACRO(98) MACRO(99) MACRO(100) MACRO(101) MACRO(102) MACRO(103) MACRO(104) MACRO(105) MACRO(106) MACRO(107) MACRO(108) MACRO(109) MACRO(110) MACRO(111) MACRO(112) MACRO(113) MACRO(114) MACRO(115) MACRO(116) MACRO(117) MACRO(118) MACRO(119) MACRO(120) MACRO(121) MACRO(122) MACRO(123) MACRO(124) MACRO(125) MACRO(126) MACRO(127) \
|
||||
MACRO(128) MACRO(129) MACRO(130) MACRO(131) MACRO(132) MACRO(133) MACRO(134) MACRO(135) MACRO(136) MACRO(137) MACRO(138) MACRO(139) MACRO(140) MACRO(141) MACRO(142) MACRO(143) MACRO(144) MACRO(145) MACRO(146) MACRO(147) MACRO(148) MACRO(149) MACRO(150) MACRO(151) MACRO(152) MACRO(153) MACRO(154) MACRO(155) MACRO(156) MACRO(157) MACRO(158) MACRO(159) MACRO(160) MACRO(161) MACRO(162) MACRO(163) MACRO(164) MACRO(165) MACRO(166) MACRO(167) MACRO(168) MACRO(169) MACRO(170) MACRO(171) MACRO(172) MACRO(173) MACRO(174) MACRO(175) MACRO(176) MACRO(177) MACRO(178) MACRO(179) MACRO(180) MACRO(181) MACRO(182) MACRO(183) MACRO(184) MACRO(185) MACRO(186) MACRO(187) MACRO(188) MACRO(189) MACRO(190) MACRO(191) MACRO(192) MACRO(193) MACRO(194) MACRO(195) MACRO(196) MACRO(197) MACRO(198) MACRO(199) MACRO(200) MACRO(201) MACRO(202) MACRO(203) MACRO(204) MACRO(205) MACRO(206) MACRO(207) MACRO(208) MACRO(209) MACRO(210) MACRO(211) MACRO(212) MACRO(213) MACRO(214) MACRO(215) MACRO(216) MACRO(217) MACRO(218) MACRO(219) MACRO(220) MACRO(221) MACRO(222) MACRO(223) MACRO(224) MACRO(225) MACRO(226) MACRO(227) MACRO(228) MACRO(229) MACRO(230) MACRO(231) MACRO(232) MACRO(233) MACRO(234) MACRO(235) MACRO(236) MACRO(237) MACRO(238) MACRO(239) MACRO(240) MACRO(241) MACRO(242) MACRO(243) MACRO(244) MACRO(245) MACRO(246) MACRO(247) MACRO(248) MACRO(249) MACRO(250) MACRO(251) MACRO(252) MACRO(253) MACRO(254) MACRO(255)
|
||||
|
||||
/*****************************************************************************************
|
||||
Error Codes
|
||||
*****************************************************************************************/
|
||||
|
||||
// success
|
||||
#ifndef ERROR_SUCCESS
|
||||
# define ERROR_SUCCESS 0
|
||||
#endif
|
||||
|
||||
// file and i/o errors (1000's)
|
||||
#define ERROR_IO_READ 1000
|
||||
#define ERROR_IO_WRITE 1001
|
||||
#define ERROR_INVALID_INPUT_FILE 1002
|
||||
#define ERROR_INVALID_OUTPUT_FILE 1003
|
||||
#define ERROR_INPUT_FILE_TOO_LARGE 1004
|
||||
#define ERROR_INPUT_FILE_UNSUPPORTED_BIT_DEPTH 1005
|
||||
#define ERROR_INPUT_FILE_UNSUPPORTED_SAMPLE_RATE 1006
|
||||
#define ERROR_INPUT_FILE_UNSUPPORTED_CHANNEL_COUNT 1007
|
||||
#define ERROR_INPUT_FILE_TOO_SMALL 1008
|
||||
#define ERROR_INVALID_CHECKSUM 1009
|
||||
#define ERROR_DECOMPRESSING_FRAME 1010
|
||||
#define ERROR_INITIALIZING_UNMAC 1011
|
||||
#define ERROR_INVALID_FUNCTION_PARAMETER 1012
|
||||
#define ERROR_UNSUPPORTED_FILE_TYPE 1013
|
||||
#define ERROR_UNSUPPORTED_FILE_VERSION 1014
|
||||
|
||||
// memory errors (2000's)
|
||||
#define ERROR_INSUFFICIENT_MEMORY 2000
|
||||
|
||||
// dll errors (3000's)
|
||||
#define ERROR_LOADING_MAC_DLL 3000
|
||||
#define ERROR_LOADING_MAC_INFO_DLL 3001
|
||||
#define ERROR_LOADING_UNMAC_DLL 3002
|
||||
|
||||
// general and misc errors
|
||||
#define ERROR_USER_STOPPED_PROCESSING 4000
|
||||
#define ERROR_SKIPPED 4001
|
||||
|
||||
// programmer errors
|
||||
#define ERROR_BAD_PARAMETER 5000
|
||||
|
||||
// IAPECompress errors
|
||||
#define ERROR_APE_COMPRESS_TOO_MUCH_DATA 6000
|
||||
|
||||
// unknown error
|
||||
#define ERROR_UNDEFINED -1
|
||||
|
||||
|
||||
#define ERROR_EXPLANATION \
|
||||
{ ERROR_IO_READ , "I/O read error" }, \
|
||||
{ ERROR_IO_WRITE , "I/O write error" }, \
|
||||
{ ERROR_INVALID_INPUT_FILE , "invalid input file" }, \
|
||||
{ ERROR_INVALID_OUTPUT_FILE , "invalid output file" }, \
|
||||
{ ERROR_INPUT_FILE_TOO_LARGE , "input file file too large" }, \
|
||||
{ ERROR_INPUT_FILE_UNSUPPORTED_BIT_DEPTH , "input file unsupported bit depth" }, \
|
||||
{ ERROR_INPUT_FILE_UNSUPPORTED_SAMPLE_RATE , "input file unsupported sample rate" }, \
|
||||
{ ERROR_INPUT_FILE_UNSUPPORTED_CHANNEL_COUNT , "input file unsupported channel count" }, \
|
||||
{ ERROR_INPUT_FILE_TOO_SMALL , "input file too small" }, \
|
||||
{ ERROR_INVALID_CHECKSUM , "invalid checksum" }, \
|
||||
{ ERROR_DECOMPRESSING_FRAME , "decompressing frame" }, \
|
||||
{ ERROR_INITIALIZING_UNMAC , "initializing unmac" }, \
|
||||
{ ERROR_INVALID_FUNCTION_PARAMETER , "invalid function parameter" }, \
|
||||
{ ERROR_UNSUPPORTED_FILE_TYPE , "unsupported file type" }, \
|
||||
{ ERROR_UNSUPPORTED_FILE_VERSION , "unsuported file version" }, \
|
||||
{ ERROR_INSUFFICIENT_MEMORY , "insufficient memory" }, \
|
||||
{ ERROR_LOADING_MAC_DLL , "loading MAC.dll" }, \
|
||||
{ ERROR_LOADING_MAC_INFO_DLL , "loading MACinfo.dll" }, \
|
||||
{ ERROR_LOADING_UNMAC_DLL , "loading unMAC.dll" }, \
|
||||
{ ERROR_USER_STOPPED_PROCESSING , "user stopped processing" }, \
|
||||
{ ERROR_SKIPPED , "skipped..." }, \
|
||||
{ ERROR_BAD_PARAMETER , "bad parameter" }, \
|
||||
{ ERROR_APE_COMPRESS_TOO_MUCH_DATA , "APE compress too much data" }, \
|
||||
{ ERROR_UNDEFINED , "undefined" }, \
|
||||
|
||||
#endif /* APE_ALL_H */
|
416
gst/monkeyaudio/libmonkeyaudio/BitArray.cpp
Normal file
416
gst/monkeyaudio/libmonkeyaudio/BitArray.cpp
Normal file
|
@ -0,0 +1,416 @@
|
|||
/************************************************************************************
|
||||
Includes
|
||||
************************************************************************************/
|
||||
#include "All.h"
|
||||
#include "BitArray.h"
|
||||
|
||||
/************************************************************************************
|
||||
Declares
|
||||
************************************************************************************/
|
||||
#define BIT_ARRAY_ELEMENTS (4096) // the number of elements in the bit array (4 MB)
|
||||
#define BIT_ARRAY_BYTES (BIT_ARRAY_ELEMENTS * 4) // the number of bytes in the bit array
|
||||
#define BIT_ARRAY_BITS (BIT_ARRAY_BYTES * 8) // the number of bits in the bit array
|
||||
|
||||
#define MAX_ELEMENT_BITS 128
|
||||
#define REFILL_BIT_THRESHOLD (BIT_ARRAY_BITS - MAX_ELEMENT_BITS)
|
||||
|
||||
#define CODE_BITS 32
|
||||
#define TOP_VALUE ((unsigned int) 1 << (CODE_BITS - 1))
|
||||
#define SHIFT_BITS (CODE_BITS - 9)
|
||||
#define EXTRA_BITS ((CODE_BITS - 2) % 8 + 1)
|
||||
#define BOTTOM_VALUE (TOP_VALUE >> 8)
|
||||
|
||||
/************************************************************************************
|
||||
Lookup tables
|
||||
************************************************************************************/
|
||||
const unsigned __int32 K_SUM_MIN_BOUNDARY[32] = {0,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536,131072,262144,524288,1048576,2097152,4194304,8388608,16777216,33554432,67108864,134217728,268435456,536870912,1073741824LU,2147483648LU,0,0,0,0};
|
||||
|
||||
#define MODEL_ELEMENTS 64
|
||||
#define RANGE_OVERFLOW_TOTAL_WIDTH 65536
|
||||
#define RANGE_OVERFLOW_SHIFT 16
|
||||
|
||||
const unsigned __int32 RANGE_TOTAL[64] = {0,14824,28224,39348,47855,53994,58171,60926,62682,63786,64463,64878,65126,65276,65365,65419,65450,65469,65480,65487,65491,65493,65494,65495,65496,65497,65498,65499,65500,65501,65502,65503,65504,65505,65506,65507,65508,65509,65510,65511,65512,65513,65514,65515,65516,65517,65518,65519,65520,65521,65522,65523,65524,65525,65526,65527,65528,65529,65530,65531,65532,65533,65534,65535};
|
||||
const unsigned __int32 RANGE_WIDTH[64] = {14824,13400,11124,8507,6139,4177,2755,1756,1104,677,415,248,150,89,54,31,19,11,7,4,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
|
||||
|
||||
#ifdef BUILD_RANGE_TABLE
|
||||
int g_aryOverflows[256] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
int g_nTotalOverflow = 0;
|
||||
#endif
|
||||
|
||||
/************************************************************************************
|
||||
Constructor
|
||||
************************************************************************************/
|
||||
CBitArray::CBitArray(CIO *pIO)
|
||||
{
|
||||
// allocate memory for the bit array
|
||||
m_pBitArray = new unsigned __int32 [BIT_ARRAY_ELEMENTS];
|
||||
memset(m_pBitArray, 0, BIT_ARRAY_BYTES);
|
||||
|
||||
// initialize other variables
|
||||
m_nCurrentBitIndex = 0;
|
||||
m_pIO = pIO;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
Destructor
|
||||
************************************************************************************/
|
||||
CBitArray::~CBitArray()
|
||||
{
|
||||
// free the bit array
|
||||
SAFE_ARRAY_DELETE(m_pBitArray)
|
||||
#ifdef BUILD_RANGE_TABLE
|
||||
OutputRangeTable();
|
||||
#endif
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
Output the bit array via the CIO (typically saves to disk)
|
||||
************************************************************************************/
|
||||
int CBitArray::OutputBitArray(BOOL bFinalize)
|
||||
{
|
||||
// write the entire file to disk
|
||||
unsigned int nBytesWritten = 0;
|
||||
unsigned int nBytesToWrite = 0;
|
||||
unsigned int nRetVal = 0;
|
||||
|
||||
if (bFinalize)
|
||||
{
|
||||
nBytesToWrite = ((m_nCurrentBitIndex >> 5) * 4) + 4;
|
||||
RETURN_ON_ERROR(m_pIO->Write(m_pBitArray, nBytesToWrite, &nBytesWritten))
|
||||
|
||||
// reset the bit pointer
|
||||
m_nCurrentBitIndex = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
nBytesToWrite = (m_nCurrentBitIndex >> 5) * 4;
|
||||
RETURN_ON_ERROR(m_pIO->Write(m_pBitArray, nBytesToWrite, &nBytesWritten))
|
||||
//return -1; //(for testing)
|
||||
|
||||
// move the last value to the front of the bit array
|
||||
m_pBitArray[0] = m_pBitArray[m_nCurrentBitIndex >> 5];
|
||||
m_nCurrentBitIndex = (m_nCurrentBitIndex & 31);
|
||||
|
||||
// zero the rest of the memory (may not need the +1 because of frame byte alignment)
|
||||
memset(&m_pBitArray[1], 0, min(nBytesToWrite + 1, BIT_ARRAY_BYTES - 1));
|
||||
}
|
||||
|
||||
//return a successfule value
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
Encodes an unsigned int to the bit array (no rice coding)
|
||||
************************************************************************************/
|
||||
int CBitArray::EncodeUnsignedLong(unsigned int n)
|
||||
{
|
||||
// make sure there are at least 8 bytes in the buffer
|
||||
if (m_nCurrentBitIndex > (BIT_ARRAY_BYTES - 8))
|
||||
{
|
||||
RETURN_ON_ERROR(OutputBitArray())
|
||||
}
|
||||
|
||||
// encode the value
|
||||
unsigned __int32 nBitArrayIndex = m_nCurrentBitIndex >> 5;
|
||||
int nBitIndex = m_nCurrentBitIndex & 31;
|
||||
|
||||
if (nBitIndex == 0)
|
||||
{
|
||||
m_pBitArray[nBitArrayIndex] = n;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pBitArray[nBitArrayIndex] |= n >> nBitIndex;
|
||||
m_pBitArray[nBitArrayIndex + 1] = n << (32 - nBitIndex);
|
||||
}
|
||||
|
||||
m_nCurrentBitIndex += 32;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
Directly encode bits to the bitstream
|
||||
************************************************************************************/
|
||||
int CBitArray::EncodeBits(unsigned int nValue, int nBits)
|
||||
{
|
||||
// make sure there is room for the data
|
||||
// this is a little slower than ensuring a huge block to start with, but it's safer
|
||||
if (m_nCurrentBitIndex > REFILL_BIT_THRESHOLD)
|
||||
{
|
||||
RETURN_ON_ERROR(OutputBitArray())
|
||||
}
|
||||
|
||||
EncodeDirect(nValue, nBits);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
Advance to a byte boundary (for frame alignment)
|
||||
************************************************************************************/
|
||||
void CBitArray::AdvanceToByteBoundary()
|
||||
{
|
||||
#if 0
|
||||
m_nCurrentBitIndex--;
|
||||
m_nCurrentBitIndex |= 7;
|
||||
m_nCurrentBitIndex++;
|
||||
#else
|
||||
while (m_nCurrentBitIndex % 8)
|
||||
m_nCurrentBitIndex++;
|
||||
#endif
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
Range encoding
|
||||
************************************************************************************/
|
||||
__inline void CBitArray::PutC(unsigned char ucValue)
|
||||
{
|
||||
m_pBitArray[m_nCurrentBitIndex >> 5] |= ucValue << (24 - (m_nCurrentBitIndex & 31));
|
||||
m_nCurrentBitIndex += 8;
|
||||
}
|
||||
|
||||
#define PUTC(VALUE) m_pBitArray[m_nCurrentBitIndex >> 5] |= ((VALUE) & 0xFF) << (24 - (m_nCurrentBitIndex & 31)); m_nCurrentBitIndex += 8;
|
||||
#define PUTC_NOCAP(VALUE) m_pBitArray[m_nCurrentBitIndex >> 5] |= (VALUE) << (24 - (m_nCurrentBitIndex & 31)); m_nCurrentBitIndex += 8;
|
||||
|
||||
__inline void CBitArray::NormalizeRangeCoder()
|
||||
{
|
||||
while (m_RangeCoderInfo.range <= BOTTOM_VALUE)
|
||||
{
|
||||
if (m_RangeCoderInfo.low < (0xFF << SHIFT_BITS)) // no carry possible --> output
|
||||
{
|
||||
PUTC(m_RangeCoderInfo.buffer);
|
||||
for ( ; m_RangeCoderInfo.help; m_RangeCoderInfo.help--) { PUTC_NOCAP(0xFF); }
|
||||
m_RangeCoderInfo.buffer = (m_RangeCoderInfo.low >> SHIFT_BITS) & 0xFF;
|
||||
}
|
||||
else if (m_RangeCoderInfo.low & TOP_VALUE) // carry now, no future carry
|
||||
{
|
||||
PUTC(m_RangeCoderInfo.buffer + 1);
|
||||
m_nCurrentBitIndex += (m_RangeCoderInfo.help * 8);
|
||||
m_RangeCoderInfo.help = 0;
|
||||
m_RangeCoderInfo.buffer = (m_RangeCoderInfo.low >> SHIFT_BITS) & 0xFF;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_RangeCoderInfo.help++;
|
||||
}
|
||||
|
||||
m_RangeCoderInfo.range <<= 8;
|
||||
m_RangeCoderInfo.low = (m_RangeCoderInfo.low << 8) & (TOP_VALUE - 1);
|
||||
}
|
||||
}
|
||||
|
||||
__inline void CBitArray::EncodeFast(int nRangeWidth, int nRangeTotal, int nShift)
|
||||
{
|
||||
// normalize
|
||||
NormalizeRangeCoder();
|
||||
|
||||
// code the value
|
||||
const int nTemp = m_RangeCoderInfo.range >> nShift;
|
||||
m_RangeCoderInfo.low += nTemp * nRangeTotal;
|
||||
m_RangeCoderInfo.range = nTemp * nRangeWidth;
|
||||
}
|
||||
|
||||
__inline void CBitArray::EncodeDirect(int nValue, int nShift)
|
||||
{
|
||||
// normalize
|
||||
NormalizeRangeCoder();
|
||||
|
||||
// code the value
|
||||
m_RangeCoderInfo.range = m_RangeCoderInfo.range >> nShift;
|
||||
m_RangeCoderInfo.low += m_RangeCoderInfo.range * nValue;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
Encode a value
|
||||
************************************************************************************/
|
||||
int CBitArray::EncodeValue(int nEncode, BIT_ARRAY_STATE & BitArrayState)
|
||||
{
|
||||
// make sure there is room for the data
|
||||
// this is a little slower than ensuring a huge block to start with, but it's safer
|
||||
if (m_nCurrentBitIndex > REFILL_BIT_THRESHOLD)
|
||||
{
|
||||
RETURN_ON_ERROR(OutputBitArray())
|
||||
}
|
||||
|
||||
// convert to unsigned
|
||||
nEncode = (nEncode > 0) ? nEncode * 2 - 1 : -nEncode * 2;
|
||||
|
||||
// get the working k
|
||||
int nTempK = (BitArrayState.k) ? BitArrayState.k - 1 : 0;
|
||||
|
||||
// update nKSum
|
||||
BitArrayState.nKSum += ((nEncode + 1) / 2) - ((BitArrayState.nKSum + 16) >> 5);
|
||||
|
||||
// update k
|
||||
if (BitArrayState.nKSum < K_SUM_MIN_BOUNDARY[BitArrayState.k])
|
||||
BitArrayState.k--;
|
||||
else if (BitArrayState.nKSum >= K_SUM_MIN_BOUNDARY[BitArrayState.k + 1])
|
||||
BitArrayState.k++;
|
||||
|
||||
// break the value into value (k bits) and overflow
|
||||
const int nOverflow = nEncode >> nTempK;
|
||||
int nValue = nEncode & ((1 << nTempK) - 1);
|
||||
|
||||
// store the overflow
|
||||
if (nOverflow < (MODEL_ELEMENTS - 1))
|
||||
{
|
||||
EncodeFast(RANGE_WIDTH[nOverflow], RANGE_TOTAL[nOverflow], RANGE_OVERFLOW_SHIFT);
|
||||
|
||||
#ifdef BUILD_RANGE_TABLE
|
||||
g_aryOverflows[nOverflow]++;
|
||||
g_nTotalOverflow++;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
// store the "special" overflow (tells that perfect k is encoded next)
|
||||
EncodeFast(RANGE_WIDTH[MODEL_ELEMENTS - 1], RANGE_TOTAL[MODEL_ELEMENTS - 1], RANGE_OVERFLOW_SHIFT);
|
||||
|
||||
#ifdef BUILD_RANGE_TABLE
|
||||
g_aryOverflows[MODEL_ELEMENTS - 1]++;
|
||||
g_nTotalOverflow++;
|
||||
#endif
|
||||
|
||||
// store the "perfect" k
|
||||
int nPerfectK = 0;
|
||||
while ((nEncode >> nPerfectK) > 0) { nPerfectK++; }
|
||||
EncodeDirect(nPerfectK, 5);
|
||||
nTempK = nPerfectK;
|
||||
nValue = nEncode;
|
||||
}
|
||||
|
||||
if (nTempK <= 16)
|
||||
{
|
||||
EncodeDirect(nValue, nTempK);
|
||||
}
|
||||
else
|
||||
{
|
||||
const int nX1 = nValue & 0xFFFF;
|
||||
const int nX2 = nValue >> 16;
|
||||
EncodeDirect(nX1, 16);
|
||||
EncodeDirect(nX2, nTempK - 16);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
Flush
|
||||
************************************************************************************/
|
||||
void CBitArray::FlushBitArray()
|
||||
{
|
||||
// advance to a byte boundary (for alignment)
|
||||
AdvanceToByteBoundary();
|
||||
|
||||
// the range coder
|
||||
m_RangeCoderInfo.low = 0; // full code range
|
||||
m_RangeCoderInfo.range = TOP_VALUE;
|
||||
m_RangeCoderInfo.buffer = 0;
|
||||
m_RangeCoderInfo.help = 0; // no bytes to follow
|
||||
}
|
||||
|
||||
void CBitArray::FlushState(BIT_ARRAY_STATE & BitArrayState)
|
||||
{
|
||||
// k and ksum
|
||||
BitArrayState.k = 10;
|
||||
BitArrayState.nKSum = (1 << BitArrayState.k) * 16;
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
Finalize
|
||||
************************************************************************************/
|
||||
void CBitArray::Finalize()
|
||||
{
|
||||
NormalizeRangeCoder();
|
||||
|
||||
unsigned int nTemp = (m_RangeCoderInfo.low >> SHIFT_BITS) + 1;
|
||||
|
||||
if (nTemp > 0xFF) // we have a carry
|
||||
{
|
||||
PutC(m_RangeCoderInfo.buffer + 1);
|
||||
for(; m_RangeCoderInfo.help; m_RangeCoderInfo.help--)
|
||||
PutC(0);
|
||||
}
|
||||
else // no carry
|
||||
{
|
||||
PutC(m_RangeCoderInfo.buffer);
|
||||
for(; m_RangeCoderInfo.help; m_RangeCoderInfo.help--)
|
||||
PutC(0xFF);
|
||||
}
|
||||
|
||||
// we must output these bytes so the decoder can properly work at the end of the stream
|
||||
PutC(nTemp & 0xFF);
|
||||
PutC(0);
|
||||
PutC(0);
|
||||
PutC(0);
|
||||
}
|
||||
|
||||
/************************************************************************************
|
||||
Build a range table (for development / debugging)
|
||||
************************************************************************************/
|
||||
#ifdef BUILD_RANGE_TABLE
|
||||
void CBitArray::OutputRangeTable()
|
||||
{
|
||||
int z;
|
||||
|
||||
if (g_nTotalOverflow == 0) return;
|
||||
|
||||
int nTotal = 0;
|
||||
int aryWidth[256]; ZeroMemory(aryWidth, 256 * 4);
|
||||
for (z = 0; z < MODEL_ELEMENTS; z++)
|
||||
{
|
||||
aryWidth[z] = int(((float(g_aryOverflows[z]) * float(65536)) + (g_nTotalOverflow / 2)) / float(g_nTotalOverflow));
|
||||
if (aryWidth[z] == 0) aryWidth[z] = 1;
|
||||
nTotal += aryWidth[z];
|
||||
}
|
||||
|
||||
z = 0;
|
||||
while (nTotal > 65536)
|
||||
{
|
||||
if (aryWidth[z] != 1)
|
||||
{
|
||||
aryWidth[z]--;
|
||||
nTotal--;
|
||||
}
|
||||
z++;
|
||||
if (z == MODEL_ELEMENTS) z = 0;
|
||||
}
|
||||
|
||||
z = 0;
|
||||
while (nTotal < 65536)
|
||||
{
|
||||
aryWidth[z++]++;
|
||||
nTotal++;
|
||||
if (z == MODEL_ELEMENTS) z = 0;
|
||||
}
|
||||
|
||||
int aryTotal[256]; ZeroMemory(aryTotal, 256 * 4);
|
||||
for (z = 0; z < MODEL_ELEMENTS; z++)
|
||||
{
|
||||
for (int q = 0; q < z; q++)
|
||||
{
|
||||
aryTotal[z] += aryWidth[q];
|
||||
}
|
||||
}
|
||||
|
||||
char buf[1024];
|
||||
sprintf(buf, "const unsigned __int32 RANGE_TOTAL[%d] = {", MODEL_ELEMENTS);
|
||||
ODS(buf);
|
||||
for (z = 0; z < MODEL_ELEMENTS; z++)
|
||||
{
|
||||
sprintf(buf, "%d,", aryTotal[z]);
|
||||
OutputDebugString(buf);
|
||||
}
|
||||
ODS("};\r\n");
|
||||
|
||||
sprintf(buf, "const unsigned __int32 RANGE_WIDTH[%d] = {", MODEL_ELEMENTS);
|
||||
ODS(buf);
|
||||
for (z = 0; z < MODEL_ELEMENTS; z++)
|
||||
{
|
||||
sprintf(buf, "%d,", aryWidth[z]);
|
||||
OutputDebugString(buf);
|
||||
}
|
||||
ODS("};\r\n\r\n");
|
||||
}
|
||||
#endif // #ifdef BUILD_RANGE_TABLE
|
65
gst/monkeyaudio/libmonkeyaudio/BitArray.h
Normal file
65
gst/monkeyaudio/libmonkeyaudio/BitArray.h
Normal file
|
@ -0,0 +1,65 @@
|
|||
#ifndef APE_BITARRAY_H
|
||||
#define APE_BITARRAY_H
|
||||
|
||||
#include "IO.h"
|
||||
|
||||
//#define BUILD_RANGE_TABLE
|
||||
|
||||
struct RANGE_CODER_STRUCT_COMPRESS
|
||||
{
|
||||
unsigned int low; // low end of interval
|
||||
unsigned int range; // length of interval
|
||||
unsigned int help; // bytes_to_follow resp. intermediate value
|
||||
unsigned char buffer; // buffer for input / output
|
||||
};
|
||||
|
||||
struct BIT_ARRAY_STATE
|
||||
{
|
||||
unsigned __int32 k;
|
||||
unsigned __int32 nKSum;
|
||||
};
|
||||
|
||||
class CBitArray
|
||||
{
|
||||
public:
|
||||
|
||||
// construction / destruction
|
||||
CBitArray(CIO *pIO);
|
||||
~CBitArray();
|
||||
|
||||
// encoding
|
||||
int EncodeUnsignedLong(unsigned int n);
|
||||
int EncodeValue(int nEncode, BIT_ARRAY_STATE & BitArrayState);
|
||||
int EncodeBits(unsigned int nValue, int nBits);
|
||||
|
||||
// output (saving)
|
||||
int OutputBitArray(BOOL bFinalize = FALSE);
|
||||
|
||||
// other functions
|
||||
void Finalize();
|
||||
void AdvanceToByteBoundary();
|
||||
__inline unsigned __int32 GetCurrentBitIndex() { return m_nCurrentBitIndex; }
|
||||
void FlushState(BIT_ARRAY_STATE & BitArrayState);
|
||||
void FlushBitArray();
|
||||
|
||||
private:
|
||||
|
||||
// data members
|
||||
unsigned __int32 * m_pBitArray;
|
||||
CIO * m_pIO;
|
||||
unsigned __int32 m_nCurrentBitIndex;
|
||||
RANGE_CODER_STRUCT_COMPRESS m_RangeCoderInfo;
|
||||
|
||||
// functions
|
||||
__inline void NormalizeRangeCoder();
|
||||
__inline void EncodeFast(int nRangeWidth, int nRangeTotal, int nShift);
|
||||
__inline void PutC(unsigned char ucValue);
|
||||
__inline void EncodeDirect(int nValue, int nShift);
|
||||
|
||||
#ifdef BUILD_RANGE_TABLE
|
||||
void OutputRangeTable();
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
#endif /* APE_BITARRAY_H */
|
94
gst/monkeyaudio/libmonkeyaudio/GlobalFunctions.cpp
Normal file
94
gst/monkeyaudio/libmonkeyaudio/GlobalFunctions.cpp
Normal file
|
@ -0,0 +1,94 @@
|
|||
#include "All.h"
|
||||
#include "GlobalFunctions.h"
|
||||
#include "IO.h"
|
||||
|
||||
#ifndef __GNUC_IA32__
|
||||
|
||||
#pragma warning( disable : 4035 )
|
||||
|
||||
extern "C" BOOL
|
||||
GetMMXAvailable ( void ) // No check for 80286 and below, code won't compile on 16 bit due to "int = 32 bit" assumption
|
||||
{
|
||||
#if defined ENABLE_ASSEMBLY
|
||||
_asm {
|
||||
pushfd
|
||||
pop eax
|
||||
mov ecx, eax
|
||||
xor eax, 0x200000
|
||||
push eax
|
||||
popfd
|
||||
pushfd
|
||||
pop eax
|
||||
cmp eax, ecx
|
||||
jz retval // no CPUID instruction available => 80386, 80486
|
||||
mov eax, 1
|
||||
CPUID
|
||||
test edx, 0x800000 // MMX available ?
|
||||
retval: setnz al
|
||||
and eax, 1
|
||||
}
|
||||
#else
|
||||
return FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
#pragma warning( default : 4035 )
|
||||
|
||||
#endif /* __GNUC_IA32__ */
|
||||
|
||||
|
||||
int ReadSafe(CIO * pIO, void * pBuffer, int nBytes)
|
||||
{
|
||||
unsigned int nBytesRead = 0;
|
||||
int nRetVal = pIO->Read(pBuffer, nBytes, &nBytesRead);
|
||||
if (nRetVal == ERROR_SUCCESS)
|
||||
{
|
||||
if (nBytes != int(nBytesRead))
|
||||
nRetVal = ERROR_IO_READ;
|
||||
}
|
||||
|
||||
return nRetVal;
|
||||
}
|
||||
|
||||
int WriteSafe(CIO * pIO, void * pBuffer, int nBytes)
|
||||
{
|
||||
unsigned int nBytesWritten = 0;
|
||||
int nRetVal = pIO->Write(pBuffer, nBytes, &nBytesWritten);
|
||||
if (nRetVal == ERROR_SUCCESS)
|
||||
{
|
||||
if (nBytes != int(nBytesWritten))
|
||||
nRetVal = ERROR_IO_WRITE;
|
||||
}
|
||||
|
||||
return nRetVal;
|
||||
}
|
||||
|
||||
BOOL FileExists ( const char* pFilename )
|
||||
{
|
||||
if ( 0 == strcmp ( pFilename, "-" ) || 0 == strcmp ( pFilename, "/dev/stdin" ) )
|
||||
return TRUE;
|
||||
#ifdef _WIN32
|
||||
BOOL bFound = FALSE;
|
||||
|
||||
WIN32_FIND_DATA WFD;
|
||||
HANDLE hFind = FindFirstFile(pFilename, &WFD);
|
||||
if (hFind != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
bFound = TRUE;
|
||||
CloseHandle(hFind);
|
||||
}
|
||||
|
||||
return bFound;
|
||||
#else
|
||||
struct stat b;
|
||||
|
||||
if ( stat ( pFilename, &b ) != 0 )
|
||||
return FALSE;
|
||||
|
||||
if ( ! S_ISREG (b.st_mode) )
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
|
||||
#endif
|
||||
}
|
26
gst/monkeyaudio/libmonkeyaudio/GlobalFunctions.h
Normal file
26
gst/monkeyaudio/libmonkeyaudio/GlobalFunctions.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
#ifndef APE_GLOBALFUNCTIONS_H
|
||||
#define APE_GLOBALFUNCTIONS_H
|
||||
|
||||
/*************************************************************************************
|
||||
Definitions
|
||||
*************************************************************************************/
|
||||
class CIO;
|
||||
|
||||
/*************************************************************************************
|
||||
Checks for MMX
|
||||
*************************************************************************************/
|
||||
extern "C" BOOL GetMMXAvailable ( void );
|
||||
|
||||
/*************************************************************************************
|
||||
Read / Write from an IO source and return failure if the number of bytes specified
|
||||
isn't read or written
|
||||
*************************************************************************************/
|
||||
int ReadSafe(CIO * pIO, void * pBuffer, int nBytes);
|
||||
int WriteSafe(CIO * pIO, void * pBuffer, int nBytes);
|
||||
|
||||
/*************************************************************************************
|
||||
Checks for the existence of a file
|
||||
*************************************************************************************/
|
||||
BOOL FileExists(const char * pFilename);
|
||||
|
||||
#endif /* APE_GLOBALFUNCTIONS_H */
|
26
gst/monkeyaudio/libmonkeyaudio/ID3Genres.h
Normal file
26
gst/monkeyaudio/libmonkeyaudio/ID3Genres.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
#ifndef APE_ID3GENRES_H
|
||||
#define APE_ID3GENRES_H
|
||||
|
||||
#define GENRE_UNDEFINED 255
|
||||
#define GENRE_COUNT 148
|
||||
|
||||
const char * const g_ID3Genre [GENRE_COUNT] = {
|
||||
"Blues", "Classic Rock", "Country", "Dance", "Disco", "Funk", "Grunge", "Hip-Hop",
|
||||
"Jazz", "Metal", "New Age", "Oldies", "Other", "Pop", "R&B", "Rap", "Reggae", "Rock", "Techno",
|
||||
"Industrial", "Alternative", "Ska", "Death Metal", "Pranks", "Soundtrack", "Euro-Techno", "Ambient",
|
||||
"Trip-Hop", "Vocal", "Jazz+Funk", "Fusion", "Trance", "Classical", "Instrumental", "Acid", "House", "Game",
|
||||
"Sound Clip", "Gospel", "Noise", "AlternRock", "Bass", "Soul", "Punk", "Space", "Meditative", "Instrumental Pop",
|
||||
"Instrumental Rock", "Ethnic", "Gothic", "Darkwave", "Techno-Industrial", "Electronic", "Pop-Folk", "Eurodance",
|
||||
"Dream", "Southern Rock", "Comedy", "Cult", "Gangsta", "Top 40", "Christian Rap", "Pop/Funk", "Jungle",
|
||||
"Native American", "Cabaret", "New Wave", "Psychadelic", "Rave", "Showtunes", "Trailer", "Lo-Fi", "Tribal",
|
||||
"Acid Punk", "Acid Jazz", "Polka", "Retro", "Musical", "Rock & Roll", "Hard Rock", "Folk", "Folk-Rock", "National Folk",
|
||||
"Swing", "Fast Fusion", "Bebop", "Latin", "Revival", "Celtic", "Bluegrass", "Avantgarde", "Gothic Rock", "Progressive Rock",
|
||||
"Psychedelic Rock", "Symphonic Rock", "Slow Rock", "Big Band", "Chorus", "Easy Listening", "Acoustic", "Humour",
|
||||
"Speech", "Chanson", "Opera", "Chamber Music", "Sonata", "Symphony", "Booty Bass", "Primus", "Porn Groove",
|
||||
"Satire", "Slow Jam", "Club", "Tango", "Samba", "Folklore", "Ballad", "Power Ballad", "Rhythmic Soul", "Freestyle",
|
||||
"Duet", "Punk Rock", "Drum Solo", "Acapella", "Euro-House", "Dance Hall", "Goa", "Drum & Bass", "Club House", "Hardcore",
|
||||
"Terror", "Indie", "BritPop", "Black Punk", "Polsk Punk", "Beat", "Christian Gangsta", "Heavy Metal", "Black Metal",
|
||||
"Crossover", "Contemporary C", "Christian Rock", "Merengue", "Salsa", "Thrash Metal", "Anime", "JPop", "SynthPop"
|
||||
};
|
||||
|
||||
#endif /* APE_ID3GENRES_H */
|
56
gst/monkeyaudio/libmonkeyaudio/IO.h
Normal file
56
gst/monkeyaudio/libmonkeyaudio/IO.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
#ifndef APE_IO_H
|
||||
#define APE_IO_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifndef FILE_BEGIN
|
||||
# define FILE_BEGIN 0
|
||||
#endif
|
||||
|
||||
#ifndef FILE_CURRENT
|
||||
# define FILE_CURRENT 1
|
||||
#endif
|
||||
|
||||
#ifndef FILE_END
|
||||
# define FILE_END 2
|
||||
#endif
|
||||
|
||||
#ifndef SEEK_SET
|
||||
# define SEEK_SET 0
|
||||
#endif
|
||||
|
||||
|
||||
class CIO
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
//construction / destruction
|
||||
CIO() { }
|
||||
virtual ~CIO() { };
|
||||
|
||||
// open / close
|
||||
virtual int Open(const char * pName) = 0;
|
||||
virtual int Close() = 0;
|
||||
|
||||
// read / write
|
||||
virtual int Read(void * pBuffer, unsigned int nBytesToRead, unsigned int * pBytesRead) = 0;
|
||||
virtual int Write(const void * pBuffer, unsigned int nBytesToWrite, unsigned int * pBytesWritten) = 0;
|
||||
|
||||
// seek
|
||||
virtual int Seek(int nDistance, unsigned int nMoveMode) = 0;
|
||||
|
||||
// creation / destruction
|
||||
virtual int Create(const char * pName) = 0;
|
||||
virtual int Delete() = 0;
|
||||
|
||||
// other functions
|
||||
virtual int SetEOF() = 0;
|
||||
|
||||
// attributes
|
||||
virtual int GetPosition() = 0;
|
||||
virtual int GetSize() = 0;
|
||||
virtual int GetName(char * pBuffer) = 0;
|
||||
};
|
||||
|
||||
#endif /* APE_IO_H */
|
151
gst/monkeyaudio/libmonkeyaudio/MACLib.cpp
Normal file
151
gst/monkeyaudio/libmonkeyaudio/MACLib.cpp
Normal file
|
@ -0,0 +1,151 @@
|
|||
#include "All.h"
|
||||
#include "MACLib.h"
|
||||
|
||||
#include "APECompress.h"
|
||||
#include "APECompressCreate.h"
|
||||
#include "APECompressCore.h"
|
||||
#include "APECompress.h"
|
||||
#include "APEDecompress.h"
|
||||
#include "APEInfo.h"
|
||||
#include "APELink.h"
|
||||
|
||||
#ifdef BACKWARDS_COMPATIBILITY
|
||||
#include "Old/APEDecompressOld.h"
|
||||
#endif
|
||||
|
||||
IAPEDecompress * CreateIAPEDecompressCore(CAPEInfo * pAPEInfo, int nStartBlock, int nFinishBlock, int * pErrorCode)
|
||||
{
|
||||
IAPEDecompress * pAPEDecompress = NULL;
|
||||
if (pAPEInfo != NULL && *pErrorCode == ERROR_SUCCESS)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (pAPEInfo->GetInfo(APE_INFO_FILE_VERSION) >= 3930)
|
||||
pAPEDecompress = new CAPEDecompress(pErrorCode, pAPEInfo, nStartBlock, nFinishBlock);
|
||||
#ifdef BACKWARDS_COMPATIBILITY
|
||||
else
|
||||
pAPEDecompress = new CAPEDecompressOld(pErrorCode, pAPEInfo, nStartBlock, nFinishBlock);
|
||||
#endif
|
||||
|
||||
if (pAPEDecompress == NULL || *pErrorCode != ERROR_SUCCESS)
|
||||
{
|
||||
SAFE_DELETE(pAPEDecompress)
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
SAFE_DELETE(pAPEDecompress)
|
||||
*pErrorCode = ERROR_UNDEFINED;
|
||||
}
|
||||
}
|
||||
|
||||
return pAPEDecompress;
|
||||
}
|
||||
|
||||
IAPEDecompress * __stdcall CreateIAPEDecompress(const char * pFilename, int * pErrorCode)
|
||||
{
|
||||
// error check the parameters
|
||||
if ((pFilename == NULL) || (strlen(pFilename) == 0))
|
||||
{
|
||||
if (pErrorCode) *pErrorCode = ERROR_BAD_PARAMETER;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// variables
|
||||
int nErrorCode = ERROR_UNDEFINED;
|
||||
CAPEInfo * pAPEInfo = NULL;
|
||||
int nStartBlock = -1; int nFinishBlock = -1;
|
||||
|
||||
// get the extension
|
||||
const char * pExtension = &pFilename[strlen(pFilename)];
|
||||
while ((pExtension > pFilename) && (*pExtension != '.'))
|
||||
pExtension--;
|
||||
|
||||
// take the appropriate action (based on the extension)
|
||||
if (_stricmp(pExtension, ".apl") == 0)
|
||||
{
|
||||
// "link" file (.apl linked large APE file)
|
||||
CAPELink APELink(pFilename);
|
||||
CAPETag * pAPETag = new CAPETag(pFilename, TRUE);
|
||||
|
||||
pAPEInfo = new CAPEInfo(&nErrorCode, APELink.m_cImageFile, pAPETag);
|
||||
nStartBlock = APELink.m_nStartBlock; nFinishBlock = APELink.m_nFinishBlock;
|
||||
}
|
||||
else
|
||||
#if 0
|
||||
if ((_stricmp(pExtension, ".mac") == 0) || (_stricmp(pExtension, ".ape") == 0))
|
||||
#endif
|
||||
{
|
||||
// plain .ape file
|
||||
pAPEInfo = new CAPEInfo(&nErrorCode, pFilename);
|
||||
}
|
||||
#if 0
|
||||
else
|
||||
{
|
||||
if (pErrorCode) *pErrorCode = ERROR_INVALID_INPUT_FILE;
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
// create and return
|
||||
IAPEDecompress * pAPEDecompress = CreateIAPEDecompressCore(pAPEInfo, nStartBlock, nFinishBlock, &nErrorCode);
|
||||
if (pErrorCode) *pErrorCode = nErrorCode;
|
||||
return pAPEDecompress;
|
||||
}
|
||||
|
||||
IAPEDecompress * __stdcall CreateIAPEDecompressEx(CIO * pIO, int * pErrorCode)
|
||||
{
|
||||
int nErrorCode = ERROR_UNDEFINED;
|
||||
CAPEInfo * pAPEInfo = new CAPEInfo(&nErrorCode, pIO);
|
||||
|
||||
IAPEDecompress * pAPEDecompress = CreateIAPEDecompressCore(pAPEInfo, -1, -1, &nErrorCode);
|
||||
if (pErrorCode) *pErrorCode = nErrorCode;
|
||||
return pAPEDecompress;
|
||||
}
|
||||
|
||||
IAPECompress * __stdcall CreateIAPECompress(int * pErrorCode)
|
||||
{
|
||||
if (pErrorCode)
|
||||
*pErrorCode = ERROR_SUCCESS;
|
||||
|
||||
return new CAPECompress();
|
||||
}
|
||||
|
||||
int __stdcall FillWaveFormatEx(WAVEFORMATEX * pWaveFormatEx, int nSampleRate, int nBitsPerSample, int nChannels)
|
||||
{
|
||||
pWaveFormatEx->cbSize = 0;
|
||||
pWaveFormatEx->nSamplesPerSec = nSampleRate;
|
||||
pWaveFormatEx->wBitsPerSample = nBitsPerSample;
|
||||
pWaveFormatEx->nChannels = nChannels;
|
||||
pWaveFormatEx->wFormatTag = 1;
|
||||
|
||||
pWaveFormatEx->nBlockAlign = (pWaveFormatEx->wBitsPerSample / 8) * pWaveFormatEx->nChannels;
|
||||
pWaveFormatEx->nAvgBytesPerSec = pWaveFormatEx->nBlockAlign * pWaveFormatEx->nSamplesPerSec;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __stdcall FillWaveHeader(WAVE_HEADER * pWAVHeader, int nAudioBytes, WAVEFORMATEX * pWaveFormatEx, int nTerminatingBytes)
|
||||
{
|
||||
try
|
||||
{
|
||||
// RIFF header
|
||||
memcpy(pWAVHeader->cRIFFHeader, "RIFF", 4);
|
||||
pWAVHeader->nRIFFBytes = (nAudioBytes + 44) - 8 + nTerminatingBytes;
|
||||
|
||||
// format header
|
||||
memcpy(pWAVHeader->cDataTypeID, "WAVE", 4);
|
||||
memcpy(pWAVHeader->cFormatHeader, "fmt ", 4);
|
||||
|
||||
// the format chunk is the first 16 bytes of a waveformatex
|
||||
pWAVHeader->nFormatBytes = 16;
|
||||
memcpy(&pWAVHeader->nFormatTag, pWaveFormatEx, 16);
|
||||
|
||||
// the data header
|
||||
memcpy(pWAVHeader->cDataHeader, "data", 4);
|
||||
pWAVHeader->nDataBytes = nAudioBytes;
|
||||
|
||||
return 0;
|
||||
}
|
||||
catch(...) { return -1; }
|
||||
}
|
393
gst/monkeyaudio/libmonkeyaudio/MACLib.h
Normal file
393
gst/monkeyaudio/libmonkeyaudio/MACLib.h
Normal file
|
@ -0,0 +1,393 @@
|
|||
/*****************************************************************************************
|
||||
Monkey's Audio MACLib.h (include for using MACLib.lib in your projects)
|
||||
Copyright (C) 2000-2002 by Matthew T. Ashland All Rights Reserved.
|
||||
|
||||
Overview:
|
||||
|
||||
There are two main interfaces... create one (using CreateIAPExxx) and go to town:
|
||||
|
||||
IAPECompress - for creating APE files
|
||||
IAPEDecompress - for decompressing and analyzing APE files
|
||||
|
||||
Note(s):
|
||||
|
||||
-unless otherwise specified, functions return ERROR_SUCCESS (0) on success and an
|
||||
error code on failure.
|
||||
|
||||
-the terminology "Sample" refers to a single sample value, and "Block" refers
|
||||
to a collection of "Channel" samples. For simplicity, MAC typically uses blocks
|
||||
everywhere so that channel mis-alignment cannot happen. (i.e. on a CD, a sample is
|
||||
2 bytes and a block is 4 bytes ([2 bytes / sample] * [2 channels] = 4 bytes))
|
||||
|
||||
Questions / Suggestions:
|
||||
|
||||
Please direct questions or comments to the Monkey's Audio developers board:
|
||||
http://www.monkeysaudio.com/cgi-bin/YaBB/YaBB.cgi -> Developers
|
||||
or, if necessary, email @ monkeysaudio.com
|
||||
*****************************************************************************************/
|
||||
|
||||
#ifndef APE_MACLIB_H
|
||||
#define APE_MACLIB_H
|
||||
|
||||
/*****************************************************************************************
|
||||
Defines
|
||||
*****************************************************************************************/
|
||||
#define COMPRESSION_LEVEL_FAST 1000
|
||||
#define COMPRESSION_LEVEL_NORMAL 2000
|
||||
#define COMPRESSION_LEVEL_HIGH 3000
|
||||
#define COMPRESSION_LEVEL_EXTRA_HIGH 4000
|
||||
#define COMPRESSION_LEVEL_INSANE_HIGH 5000
|
||||
#define COMPRESSION_LEVEL_BRAINDEAD_HIGH 6000
|
||||
|
||||
#define MAC_FORMAT_FLAG_8_BIT 1 // is 8-bit
|
||||
#define MAC_FORMAT_FLAG_CRC 2 // uses the new CRC32 error detection
|
||||
#define MAC_FORMAT_FLAG_HAS_PEAK_LEVEL 4 // unsigned __int32 Peak_Level after the header
|
||||
#define MAC_FORMAT_FLAG_24_BIT 8 // is 24-bit
|
||||
#define MAC_FORMAT_FLAG_HAS_SEEK_ELEMENTS 16 // has the number of seek elements after the peak level
|
||||
#define MAC_FORMAT_FLAG_CREATE_WAV_HEADER 32 // create the wave header on decompression (not stored)
|
||||
|
||||
#define CREATE_WAV_HEADER_ON_DECOMPRESSION -1
|
||||
#define MAX_AUDIO_BYTES_UNKNOWN -1
|
||||
|
||||
typedef void (__stdcall * APE_PROGRESS_CALLBACK) (int);
|
||||
|
||||
/*****************************************************************************************
|
||||
WAV header structure
|
||||
*****************************************************************************************/
|
||||
struct WAVE_HEADER
|
||||
{
|
||||
// RIFF header
|
||||
char cRIFFHeader[4];
|
||||
unsigned int nRIFFBytes;
|
||||
|
||||
// data type
|
||||
char cDataTypeID[4];
|
||||
|
||||
// wave format
|
||||
char cFormatHeader[4];
|
||||
unsigned int nFormatBytes;
|
||||
|
||||
unsigned short nFormatTag;
|
||||
unsigned short nChannels;
|
||||
unsigned int nSamplesPerSec;
|
||||
unsigned int nAvgBytesPerSec;
|
||||
unsigned short nBlockAlign;
|
||||
unsigned short nBitsPerSample;
|
||||
|
||||
// data chunk header
|
||||
char cDataHeader[4];
|
||||
unsigned int nDataBytes;
|
||||
};
|
||||
|
||||
/*****************************************************************************************
|
||||
APE header structure (what's at the front of an APE file)
|
||||
*****************************************************************************************/
|
||||
#define APE_HEADER_BYTES 32
|
||||
struct APE_HEADER
|
||||
{
|
||||
char cID[4]; // should equal 'MAC '
|
||||
unsigned __int16 nVersion; // version number * 1000 (3.81 = 3810)
|
||||
unsigned __int16 nCompressionLevel; // the compression level
|
||||
unsigned __int16 nFormatFlags; // any format flags (for future use)
|
||||
unsigned __int16 nChannels; // the number of channels (1 or 2)
|
||||
unsigned __int32 nSampleRate; // the sample rate (typically 44100)
|
||||
unsigned __int32 nHeaderBytes; // the bytes after the MAC header that compose the WAV header
|
||||
unsigned __int32 nTerminatingBytes; // the bytes after that raw data (for extended info)
|
||||
unsigned __int32 nTotalFrames; // the number of frames in the file
|
||||
unsigned __int32 nFinalFrameBlocks; // the number of samples in the final frame
|
||||
};
|
||||
|
||||
/*************************************************************************************************
|
||||
Classes (fully defined elsewhere)
|
||||
*************************************************************************************************/
|
||||
class CIO;
|
||||
class CInputSource;
|
||||
|
||||
/*************************************************************************************************
|
||||
IAPEDecompress fields - used when querying for information
|
||||
|
||||
Note(s):
|
||||
-the distinction between APE_INFO_XXXX and APE_DECOMPRESS_XXXX is that the first is querying the APE
|
||||
information engine, and the other is querying the decompressor, and since the decompressor can be
|
||||
a range of an APE file (for APL), differences will arise. Typically, use the APE_DECOMPRESS_XXXX
|
||||
fields when querying for info about the length, etc. so APL will work properly.
|
||||
(i.e. (APE_INFO_TOTAL_BLOCKS != APE_DECOMPRESS_TOTAL_BLOCKS) for APL files)
|
||||
*************************************************************************************************/
|
||||
enum APE_DECOMPRESS_FIELDS
|
||||
{
|
||||
APE_INFO_FILE_VERSION = 1000, // version of the APE file * 1000 (3.93 = 3930) [ignored, ignored]
|
||||
APE_INFO_COMPRESSION_LEVEL = 1001, // compression level of the APE file [ignored, ignored]
|
||||
APE_INFO_FORMAT_FLAGS = 1002, // format flags of the APE file [ignored, ignored]
|
||||
APE_INFO_SAMPLE_RATE = 1003, // sample rate (Hz) [ignored, ignored]
|
||||
APE_INFO_BITS_PER_SAMPLE = 1004, // bits per sample [ignored, ignored]
|
||||
APE_INFO_BYTES_PER_SAMPLE = 1005, // number of bytes per sample [ignored, ignored]
|
||||
APE_INFO_CHANNELS = 1006, // channels [ignored, ignored]
|
||||
APE_INFO_BLOCK_ALIGN = 1007, // block alignment [ignored, ignored]
|
||||
APE_INFO_BLOCKS_PER_FRAME = 1008, // number of blocks in a frame (frames are used internally) [ignored, ignored]
|
||||
APE_INFO_FINAL_FRAME_BLOCKS = 1009, // blocks in the final frame (frames are used internally) [ignored, ignored]
|
||||
APE_INFO_TOTAL_FRAMES = 1010, // total number frames (frames are used internally) [ignored, ignored]
|
||||
APE_INFO_WAV_HEADER_BYTES = 1011, // header bytes of the decompressed WAV [ignored, ignored]
|
||||
APE_INFO_WAV_TERMINATING_BYTES = 1012, // terminating bytes of the decompressed WAV [ignored, ignored]
|
||||
APE_INFO_WAV_DATA_BYTES = 1013, // data bytes of the decompressed WAV [ignored, ignored]
|
||||
APE_INFO_WAV_TOTAL_BYTES = 1014, // total bytes of the decompressed WAV [ignored, ignored]
|
||||
APE_INFO_APE_TOTAL_BYTES = 1015, // total bytes of the APE file [ignored, ignored]
|
||||
APE_INFO_TOTAL_BLOCKS = 1016, // total blocks of audio data [ignored, ignored]
|
||||
APE_INFO_LENGTH_MS = 1017, // length in ms (1 sec = 1000 ms) [ignored, ignored]
|
||||
APE_INFO_AVERAGE_BITRATE = 1018, // average bitrate of the APE [ignored, ignored]
|
||||
APE_INFO_FRAME_BITRATE = 1019, // bitrate of specified APE frame [frame index, ignored]
|
||||
APE_INFO_DECOMPRESSED_BITRATE = 1020, // bitrate of the decompressed WAV [ignored, ignored]
|
||||
APE_INFO_PEAK_LEVEL = 1021, // peak audio level (-1 is unknown) [ignored, ignored]
|
||||
APE_INFO_SEEK_BIT = 1022, // bit offset [frame index, ignored]
|
||||
APE_INFO_SEEK_BYTE = 1023, // byte offset [frame index, ignored]
|
||||
APE_INFO_WAV_HEADER_DATA = 1024, // error code [buffer *, max bytes]
|
||||
APE_INFO_WAV_TERMINATING_DATA = 1025, // error code [buffer *, max bytes]
|
||||
APE_INFO_WAVEFORMATEX = 1026, // error code [waveformatex *, ignored]
|
||||
APE_INFO_IO_SOURCE = 1027, // I/O source (CIO *) [ignored, ignored]
|
||||
APE_INFO_FRAME_BYTES = 1028, // bytes (compressed) of the frame [frame index, ignored]
|
||||
APE_INFO_FRAME_BLOCKS = 1029, // blocks in a given frame [frame index, ignored]
|
||||
APE_INFO_TAG = 1030, // point to tag (CAPETag *) [ignored, ignored]
|
||||
|
||||
APE_DECOMPRESS_CURRENT_BLOCK = 2000, // current block location [ignored, ignored]
|
||||
APE_DECOMPRESS_CURRENT_MS = 2001, // current millisecond location [ignored, ignored]
|
||||
APE_DECOMPRESS_TOTAL_BLOCKS = 2002, // total blocks in the decompressors range [ignored, ignored]
|
||||
APE_DECOMPRESS_LENGTH_MS = 2003, // total blocks in the decompressors range [ignored, ignored]
|
||||
APE_DECOMPRESS_CURRENT_BITRATE = 2004, // current bitrate [ignored, ignored]
|
||||
APE_DECOMPRESS_AVERAGE_BITRATE = 2005 // average bitrate (works with ranges) [ignored, ignored]
|
||||
};
|
||||
|
||||
/*************************************************************************************************
|
||||
IAPEDecompress - interface for working with existing APE files (decoding, seeking, analyzing, etc.)
|
||||
*************************************************************************************************/
|
||||
class IAPEDecompress
|
||||
{
|
||||
public:
|
||||
|
||||
// destructor (needed so implementation's destructor will be called)
|
||||
virtual ~IAPEDecompress() {}
|
||||
|
||||
/*********************************************************************************************
|
||||
* Decompress / Seek
|
||||
*********************************************************************************************/
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// GetData(...) - gets raw decompressed audio
|
||||
//
|
||||
// Parameters:
|
||||
// char * pBuffer
|
||||
// a pointer to a buffer to put the data into
|
||||
// int nBlocks
|
||||
// the number of audio blocks desired (see note at intro about blocks vs. samples)
|
||||
// int * pBlocksRetrieved
|
||||
// the number of blocks actually retrieved (could be less at end of file or on critical failure)
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
virtual int GetData(char * pBuffer, int nBlocks, int * pBlocksRetrieved) = 0;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Seek(...) - seeks
|
||||
//
|
||||
// Parameters:
|
||||
// int nBlockOffset
|
||||
// the block to seek to (see note at intro about blocks vs. samples)
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
virtual int Seek(int nBlockOffset) = 0;
|
||||
|
||||
/*********************************************************************************************
|
||||
* Get Information
|
||||
*********************************************************************************************/
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// GetInfo(...) - get information about the APE file or the state of the decompressor
|
||||
//
|
||||
// Parameters:
|
||||
// APE_DECOMPRESS_FIELDS Field
|
||||
// the field we're querying (see APE_DECOMPRESS_FIELDS above for more info)
|
||||
// int nParam1
|
||||
// generic parameter... usage is listed in APE_DECOMPRESS_FIELDS
|
||||
// int nParam2
|
||||
// generic parameter... usage is listed in APE_DECOMPRESS_FIELDS
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
virtual int GetInfo(APE_DECOMPRESS_FIELDS Field, int nParam1 = 0, int nParam2 = 0) = 0;
|
||||
};
|
||||
|
||||
/*************************************************************************************************
|
||||
IAPECompress - interface for creating APE files
|
||||
|
||||
Usage:
|
||||
|
||||
To create an APE file, you Start(...), then add data (in a variety of ways), then Finish(...)
|
||||
*************************************************************************************************/
|
||||
class IAPECompress
|
||||
{
|
||||
public:
|
||||
|
||||
// destructor (needed so implementation's destructor will be called)
|
||||
virtual ~IAPECompress() {}
|
||||
|
||||
/*********************************************************************************************
|
||||
* Start
|
||||
*********************************************************************************************/
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Start(...) / StartEx(...) - starts encoding
|
||||
//
|
||||
// Parameters:
|
||||
// CIO * pioOutput / const char * pFilename
|
||||
// the output... either a filename or an I/O source
|
||||
// WAVEFORMATEX * pwfeInput
|
||||
// format of the audio to encode (use FillWaveFormatEx() if necessary)
|
||||
// int nMaxAudioBytes
|
||||
// the absolute maximum audio bytes that will be encoded... encoding fails with a
|
||||
// ERROR_APE_COMPRESS_TOO_MUCH_DATA if you attempt to encode more than specified here
|
||||
// (if unknown, use MAX_AUDIO_BYTES_UNKNOWN to allocate as much storage in the seek table as
|
||||
// possible... limit is then 2 GB of data (~4 hours of CD music)... this wastes around
|
||||
// 30kb, so only do it if completely necessary)
|
||||
// int nCompressionLevel
|
||||
// the compression level for the APE file (fast - extra high)
|
||||
// (note: extra-high is much slower for little gain)
|
||||
// const unsigned char * pHeaderData
|
||||
// a pointer to a buffer containing the WAV header (data before the data block in the WAV)
|
||||
// (note: use NULL for on-the-fly encoding... see next parameter)
|
||||
// int nHeaderBytes
|
||||
// number of bytes in the header data buffer (use CREATE_WAV_HEADER_ON_DECOMPRESSION and
|
||||
// NULL for the pHeaderData and MAC will automatically create the appropriate WAV header
|
||||
// on decompression)
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
virtual int Start(const char * pOutputFilename, const WAVEFORMATEX * pwfeInput,
|
||||
int nMaxAudioBytes = MAX_AUDIO_BYTES_UNKNOWN, int nCompressionLevel = COMPRESSION_LEVEL_NORMAL,
|
||||
const unsigned char * pHeaderData = NULL, int nHeaderBytes = CREATE_WAV_HEADER_ON_DECOMPRESSION) = 0;
|
||||
|
||||
virtual int StartEx(CIO * pioOutput, const WAVEFORMATEX * pwfeInput,
|
||||
int nMaxAudioBytes = MAX_AUDIO_BYTES_UNKNOWN, int nCompressionLevel = COMPRESSION_LEVEL_NORMAL,
|
||||
const unsigned char * pHeaderData = NULL, int nHeaderBytes = CREATE_WAV_HEADER_ON_DECOMPRESSION) = 0;
|
||||
|
||||
/*********************************************************************************************
|
||||
* Add / Compress Data
|
||||
* - there are 3 ways to add data:
|
||||
* 1) simple call AddData(...)
|
||||
* 2) lock MAC's buffer, copy into it, and unlock (LockBuffer(...) / UnlockBuffer(...))
|
||||
* 3) from an I/O source (AddDataFromInputSource(...))
|
||||
*********************************************************************************************/
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// AddData(...) - adds data to the encoder
|
||||
//
|
||||
// Parameters:
|
||||
// unsigned char * pData
|
||||
// a pointer to a buffer containing the raw audio data
|
||||
// int nBytes
|
||||
// the number of bytes in the buffer
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
virtual int AddData(unsigned char * pData, int nBytes) = 0;
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// GetBufferBytesAvailable(...) - returns the number of bytes available in the buffer
|
||||
// (helpful when locking)
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
virtual int GetBufferBytesAvailable() = 0;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// LockBuffer(...) - locks MAC's buffer so we can copy into it
|
||||
//
|
||||
// Parameters:
|
||||
// int * pBytesAvailable
|
||||
// returns the number of bytes available in the buffer (DO NOT COPY MORE THAN THIS IN)
|
||||
//
|
||||
// Return:
|
||||
// pointer to the buffer (add at that location)
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
virtual unsigned char * LockBuffer(int * pBytesAvailable) = 0;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// UnlockBuffer(...) - releases the buffer
|
||||
//
|
||||
// Parameters:
|
||||
// int nBytesAdded
|
||||
// the number of bytes copied into the buffer
|
||||
// BOOL bProcess
|
||||
// whether MAC should process as much as possible of the buffer
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
virtual int UnlockBuffer(int nBytesAdded, BOOL bProcess = TRUE) = 0;
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// AddDataFromInputSource(...) - use a CInputSource (input source) to add data
|
||||
//
|
||||
// Parameters:
|
||||
// CInputSource * pInputSource
|
||||
// a pointer to the input source
|
||||
// int nMaxBytes
|
||||
// the maximum number of bytes to let MAC add (-1 if MAC can add any amount)
|
||||
// int * pBytesAdded
|
||||
// returns the number of bytes added from the I/O source
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
virtual int AddDataFromInputSource(CInputSource * pInputSource, int nMaxBytes = -1, int * pBytesAdded = NULL) = 0;
|
||||
|
||||
/*********************************************************************************************
|
||||
* Finish / Kill
|
||||
*********************************************************************************************/
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Finish(...) - ends encoding and finalizes the file
|
||||
//
|
||||
// Parameters:
|
||||
// unsigned char * pTerminatingData
|
||||
// a pointer to a buffer containing the information to place at the end of the APE file
|
||||
// (comprised of the WAV terminating data (data after the data block in the WAV) followed
|
||||
// by any tag information)
|
||||
// int nTerminatingBytes
|
||||
// number of bytes in the terminating data buffer
|
||||
// int nWAVTerminatingBytes
|
||||
// the number of bytes of the terminating data buffer that should be appended to a decoded
|
||||
// WAV file (it's basically nTerminatingBytes - the bytes that make up the tag)
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
virtual int Finish(unsigned char * pTerminatingData, int nTerminatingBytes, int nWAVTerminatingBytes) = 0;
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Kill(...) - stops encoding and deletes the output file
|
||||
// --- NOT CURRENTLY IMPLEMENTED ---
|
||||
//////////////////////////////////////////////////////////////////////////////////////////////
|
||||
virtual int Kill() = 0;
|
||||
};
|
||||
|
||||
/*************************************************************************************************
|
||||
Functions to create the interfaces
|
||||
|
||||
Usage:
|
||||
Interface creation returns a NULL pointer on failure (and fills error code if it was passed in)
|
||||
|
||||
Usage example:
|
||||
int nErrorCode;
|
||||
IAPEDecompress * pAPEDecompress = CreateIAPEDecompress("c:\\1.ape", &nErrorCode);
|
||||
if (pAPEDecompress == NULL)
|
||||
{
|
||||
// failure... nErrorCode will have specific code
|
||||
}
|
||||
|
||||
*************************************************************************************************/
|
||||
extern "C"
|
||||
{
|
||||
IAPEDecompress * __stdcall CreateIAPEDecompress(const char * pFilename, int * pErrorCode = NULL);
|
||||
IAPEDecompress * __stdcall CreateIAPEDecompressEx(CIO * pIO, int * pErrorCode = NULL);
|
||||
IAPECompress * __stdcall CreateIAPECompress(int * pErrorCode = NULL);
|
||||
}
|
||||
|
||||
/*************************************************************************************************
|
||||
Simple functions - see the SDK sample projects for usage examples
|
||||
*************************************************************************************************/
|
||||
extern "C"
|
||||
{
|
||||
// process whole files
|
||||
DLLEXPORT int __stdcall CompressFile(const char * pInputFile, const char * pOutputFile, int nCompressionLevel = COMPRESSION_LEVEL_NORMAL, int * pPercentageDone = NULL, APE_PROGRESS_CALLBACK ProgressCallback = 0, int * pKillFlag = NULL);
|
||||
DLLEXPORT int __stdcall DecompressFile(const char * pInputFilename, const char * pOutputFilename, int * pPercentageDone, APE_PROGRESS_CALLBACK ProgressCallback, int * pKillFlag);
|
||||
DLLEXPORT int __stdcall ConvertFile(const char * pInputFilename, const char * pOutputFilename, int nCompressionLevel, int * pPercentageDone, APE_PROGRESS_CALLBACK ProgressCallback, int * pKillFlag);
|
||||
DLLEXPORT int __stdcall VerifyFile(const char * pInputFilename, int * pPercentageDone, APE_PROGRESS_CALLBACK ProgressCallback, int * pKillFlag);
|
||||
|
||||
// helper functions
|
||||
DLLEXPORT int __stdcall FillWaveFormatEx(WAVEFORMATEX * pWaveFormatEx, int nSampleRate = 44100, int nBitsPerSample = 16, int nChannels = 2);
|
||||
DLLEXPORT int __stdcall FillWaveHeader(WAVE_HEADER * pWAVHeader, int nAudioBytes, WAVEFORMATEX * pWaveFormatEx, int nTerminatingBytes = 0);
|
||||
}
|
||||
|
||||
#endif /* APE_MACLIB_H */
|
90
gst/monkeyaudio/libmonkeyaudio/MACProgressHelper.cpp
Normal file
90
gst/monkeyaudio/libmonkeyaudio/MACProgressHelper.cpp
Normal file
|
@ -0,0 +1,90 @@
|
|||
// MACProgressHelper.cpp: implementation of the CMACProgressHelper class.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
#include "All.h"
|
||||
#include "MACProgressHelper.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Construction/Destruction
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
CMACProgressHelper::CMACProgressHelper(int nTotalSteps, int * pPercentageDone, APE_PROGRESS_CALLBACK ProgressCallback, int * pKillFlag)
|
||||
{
|
||||
m_pKillFlag = pKillFlag;
|
||||
|
||||
m_bUseCallback = FALSE;
|
||||
if (ProgressCallback != NULL)
|
||||
{
|
||||
m_bUseCallback = TRUE;
|
||||
m_CallbackFunction = ProgressCallback;
|
||||
}
|
||||
|
||||
m_pPercentageDone = pPercentageDone;
|
||||
|
||||
m_nTotalSteps = nTotalSteps;
|
||||
m_nCurrentStep = 0;
|
||||
m_nLastCallbackFiredPercentageDone = 0;
|
||||
|
||||
UpdateProgress(0);
|
||||
}
|
||||
|
||||
CMACProgressHelper::~CMACProgressHelper()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void CMACProgressHelper::UpdateProgress(int nCurrentStep, BOOL bForceUpdate)
|
||||
{
|
||||
//update the step
|
||||
if (nCurrentStep == -1)
|
||||
m_nCurrentStep++;
|
||||
else
|
||||
m_nCurrentStep = nCurrentStep;
|
||||
|
||||
//figure the percentage done
|
||||
float fPercentageDone = float(m_nCurrentStep) / float(max(m_nTotalSteps, 1));
|
||||
int nPercentageDone = (int) (fPercentageDone * 1000 * 100);
|
||||
if (nPercentageDone > 100000) nPercentageDone = 100000;
|
||||
|
||||
//update the percent done pointer
|
||||
if (m_pPercentageDone)
|
||||
{
|
||||
*m_pPercentageDone = nPercentageDone;
|
||||
}
|
||||
|
||||
//fire the callback
|
||||
if (m_bUseCallback)
|
||||
{
|
||||
if (bForceUpdate || (nPercentageDone - m_nLastCallbackFiredPercentageDone) >= 1000)
|
||||
{
|
||||
m_CallbackFunction(nPercentageDone);
|
||||
m_nLastCallbackFiredPercentageDone = nPercentageDone;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
int CMACProgressHelper::ProcessKillFlag(BOOL bSleep)
|
||||
{
|
||||
//process any messages (allows repaint, etc.)
|
||||
if (bSleep)
|
||||
{
|
||||
PUMP_MESSAGE_LOOP
|
||||
}
|
||||
|
||||
if (m_pKillFlag)
|
||||
{
|
||||
while (*m_pKillFlag == KILL_FLAG_PAUSE)
|
||||
{
|
||||
SLEEP(50);
|
||||
PUMP_MESSAGE_LOOP
|
||||
}
|
||||
|
||||
if ((*m_pKillFlag != KILL_FLAG_CONTINUE) && (*m_pKillFlag != KILL_FLAG_PAUSE))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
42
gst/monkeyaudio/libmonkeyaudio/MACProgressHelper.h
Normal file
42
gst/monkeyaudio/libmonkeyaudio/MACProgressHelper.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
// MACProgressHelper.h: interface for the CMACProgressHelper class.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if !defined(AFX_MACPROGRESSHELPER_H__5ACFF299_B004_4A19_85D9_CC49296D5611__INCLUDED_)
|
||||
#define AFX_MACPROGRESSHELPER_H__5ACFF299_B004_4A19_85D9_CC49296D5611__INCLUDED_
|
||||
|
||||
#if _MSC_VER > 1000
|
||||
#pragma once
|
||||
#endif // _MSC_VER > 1000
|
||||
|
||||
#define KILL_FLAG_CONTINUE 0
|
||||
#define KILL_FLAG_PAUSE -1
|
||||
|
||||
typedef void (__stdcall * APE_PROGRESS_CALLBACK) (int);
|
||||
|
||||
class CMACProgressHelper
|
||||
{
|
||||
public:
|
||||
CMACProgressHelper(int nTotalSteps, int *pPercentageDone, APE_PROGRESS_CALLBACK ProgressCallback, int *pKillFlag);
|
||||
virtual ~CMACProgressHelper();
|
||||
|
||||
void UpdateProgress(int nCurrentStep = -1, BOOL bForceUpdate = FALSE);
|
||||
void UpdateProgressComplete() { UpdateProgress(m_nTotalSteps, TRUE); }
|
||||
|
||||
int ProcessKillFlag(BOOL bSleep = TRUE);
|
||||
|
||||
private:
|
||||
|
||||
BOOL m_bUseCallback;
|
||||
APE_PROGRESS_CALLBACK m_CallbackFunction;
|
||||
|
||||
int *m_pPercentageDone;
|
||||
|
||||
int m_nTotalSteps;
|
||||
int m_nCurrentStep;
|
||||
int m_nLastCallbackFiredPercentageDone;
|
||||
|
||||
int *m_pKillFlag;
|
||||
};
|
||||
|
||||
#endif // !defined(AFX_MACPROGRESSHELPER_H__5ACFF299_B004_4A19_85D9_CC49296D5611__INCLUDED_)
|
29
gst/monkeyaudio/libmonkeyaudio/Makefile.am
Normal file
29
gst/monkeyaudio/libmonkeyaudio/Makefile.am
Normal file
|
@ -0,0 +1,29 @@
|
|||
noinst_LTLIBRARIES = libmonkeyaudio.la
|
||||
|
||||
libmonkeyaudio_la_CXXFLAGS =
|
||||
libmonkeyaudio_la_LDFLAGS =
|
||||
libmonkeyaudio_la_SOURCES = APECompress.cpp \
|
||||
APECompressCore.cpp \
|
||||
APECompressCreate.cpp \
|
||||
APEDecompress.cpp \
|
||||
APEInfo.cpp \
|
||||
APELink.cpp \
|
||||
APESimple.cpp \
|
||||
APETag.cpp \
|
||||
BitArray.cpp \
|
||||
MACLib.cpp \
|
||||
MACProgressHelper.cpp \
|
||||
NNFilter.cpp \
|
||||
NewPredictor.cpp \
|
||||
Prepare.cpp \
|
||||
UnBitArray.cpp \
|
||||
UnBitArrayBase.cpp \
|
||||
WAVInputSource.cpp \
|
||||
GlobalFunctions.cpp
|
||||
|
||||
noinst_HEADERS = All.h APEDecompress.h BitArray.h NNFilter.h RollBuffer.h UnBitArrayBase.h \
|
||||
APECompressCore.h APEInfo.h GlobalFunctions.h MACLib.h NoWindows.h ScaledFirstOrderFilter.h \
|
||||
UnBitArray.h APECompressCreate.h APELink.h ID3Genres.h MACProgressHelper.h Predictor.h \
|
||||
SmartPtr.h WAVInputSource.h APECompress.h APETag.h IO.h NewPredictor.h Prepare.h StdLibFileIO.h
|
||||
|
||||
EXTRA_DIST = changes.txt
|
249
gst/monkeyaudio/libmonkeyaudio/NNFilter.cpp
Normal file
249
gst/monkeyaudio/libmonkeyaudio/NNFilter.cpp
Normal file
|
@ -0,0 +1,249 @@
|
|||
#include "All.h"
|
||||
#include "GlobalFunctions.h"
|
||||
#include "NNFilter.h"
|
||||
|
||||
CNNFilter::CNNFilter(int nOrder, int nShift)
|
||||
{
|
||||
if ( nOrder <= 0 || (nOrder & 15) != 0 )
|
||||
throw (1);
|
||||
m_nOrder = nOrder;
|
||||
m_nShift = nShift;
|
||||
m_nRoundAdd = 1 << (nShift - 1);
|
||||
|
||||
m_bMMXAvailable = GetMMXAvailable();
|
||||
|
||||
m_rbInput . Create ( NN_WINDOW_ELEMENTS, m_nOrder );
|
||||
m_rbDeltaM . Create ( NN_WINDOW_ELEMENTS, m_nOrder );
|
||||
m_paryM = new short [m_nOrder];
|
||||
|
||||
if ( ( (int) & m_rbInput [0] ) & 7 )
|
||||
fprintf ( stderr, "m_rbInput misaligned, performance loss\n" );
|
||||
if ( ( (int) & m_rbDeltaM [0] ) & 7 )
|
||||
fprintf ( stderr, "m_rbDeltaM misaligned, performance loss\n" );
|
||||
if ( ( (int) & m_paryM [0] ) & 7 )
|
||||
fprintf ( stderr, "m_paryM misaligned, performance loss\n" );
|
||||
}
|
||||
|
||||
CNNFilter::~CNNFilter()
|
||||
{
|
||||
SAFE_ARRAY_DELETE(m_paryM)
|
||||
}
|
||||
|
||||
void CNNFilter::Flush()
|
||||
{
|
||||
memset(&m_paryM[0], 0, m_nOrder * sizeof(short));
|
||||
m_rbInput.Flush();
|
||||
m_rbDeltaM.Flush();
|
||||
}
|
||||
|
||||
short CNNFilter ::
|
||||
GetSaturatedShortFromInt ( int nValue )
|
||||
{
|
||||
if ( (short) nValue != nValue )
|
||||
nValue = (nValue >> 31) ^ 0x7FFF;
|
||||
return (short) nValue;
|
||||
}
|
||||
|
||||
int CNNFilter::Compress(int nInput)
|
||||
{
|
||||
int nDotProduct;
|
||||
int nOutput;
|
||||
|
||||
// convert the input to a short and store it
|
||||
m_rbInput[0] = GetSaturatedShortFromInt ( nInput );
|
||||
|
||||
//fprintf ( stderr, "Enter Dot\n" );
|
||||
nDotProduct = CalculateDotProduct ( & m_rbInput [-m_nOrder], & m_paryM [0], m_nOrder ); // figure a dot product
|
||||
//fprintf ( stderr, "Leave Dot\n" );
|
||||
|
||||
// calculate the output
|
||||
nOutput = nInput - ((nDotProduct + m_nRoundAdd) >> m_nShift);
|
||||
|
||||
// adapt
|
||||
//fprintf ( stderr, "Enter Adapt\n" );
|
||||
Adapt ( & m_paryM [0], & m_rbDeltaM [-m_nOrder], -nOutput, m_nOrder );
|
||||
//fprintf ( stderr, "Leave Adapt\n" );
|
||||
m_rbDeltaM[ 0] = (nInput == 0) ? 0 : ((nInput >> 28) & 8) - 4; // -4, 0, +4
|
||||
m_rbDeltaM[-4] >>= 1;
|
||||
m_rbDeltaM[-8] >>= 1;
|
||||
|
||||
// increment and roll if necessary
|
||||
m_rbInput .IncrementSafe ();
|
||||
m_rbDeltaM.IncrementSafe ();
|
||||
|
||||
return nOutput;
|
||||
}
|
||||
|
||||
|
||||
int CNNFilter::Decompress(int nInput)
|
||||
{
|
||||
int nDotProduct;
|
||||
int nOutput;
|
||||
|
||||
//fprintf ( stderr, "Enter Dot\n" );
|
||||
nDotProduct = CalculateDotProduct ( & m_rbInput [-m_nOrder], & m_paryM [0], m_nOrder ); // figure a dot product
|
||||
//fprintf ( stderr, "Leave Dot\n" );
|
||||
|
||||
// adapt
|
||||
//fprintf ( stderr, "Enter Adapt\n" );
|
||||
Adapt ( & m_paryM [0], & m_rbDeltaM [-m_nOrder], -nInput, m_nOrder );
|
||||
//fprintf ( stderr, "Leave Adapt\n" );
|
||||
|
||||
// store the output value
|
||||
nOutput = nInput + ((nDotProduct + m_nRoundAdd) >> m_nShift);
|
||||
|
||||
// update the input buffer
|
||||
m_rbInput [ 0] = GetSaturatedShortFromInt (nOutput);
|
||||
|
||||
m_rbDeltaM[ 0] = (nOutput == 0) ? 0 : ((nOutput >> 28) & 8) - 4; // -4, 0, +4
|
||||
m_rbDeltaM[-4] >>= 1;
|
||||
m_rbDeltaM[-8] >>= 1;
|
||||
|
||||
// increment and roll if necessary
|
||||
m_rbInput .IncrementSafe ();
|
||||
m_rbDeltaM.IncrementSafe ();
|
||||
|
||||
return nOutput;
|
||||
}
|
||||
|
||||
|
||||
#ifndef __GNUC_IA32__
|
||||
|
||||
void CNNFilter ::
|
||||
Adapt ( short* pM, const short* pAdapt, int nDirection, int nOrder )
|
||||
{
|
||||
|
||||
#ifdef ENABLE_ASSEMBLY
|
||||
|
||||
if ( m_bMMXAvailable ) {
|
||||
_asm {
|
||||
mov eax, pM
|
||||
mov ecx, pAdapt
|
||||
mov edx, nOrder
|
||||
shr edx, 4
|
||||
|
||||
cmp nDirection, 0
|
||||
jle AdaptSub
|
||||
|
||||
AdaptAddLoop:
|
||||
movq mm0, [eax]
|
||||
paddw mm0, [ecx]
|
||||
movq [eax], mm0
|
||||
movq mm1, [eax + 8]
|
||||
paddw mm1, [ecx + 8]
|
||||
movq [eax + 8], mm1
|
||||
movq mm2, [eax + 16]
|
||||
paddw mm2, [ecx + 16]
|
||||
movq [eax + 16], mm2
|
||||
movq mm3, [eax + 24]
|
||||
paddw mm3, [ecx + 24]
|
||||
movq [eax + 24], mm3
|
||||
add eax, 32
|
||||
add ecx, 32
|
||||
dec edx
|
||||
jnz AdaptAddLoop
|
||||
|
||||
emms
|
||||
jmp AdaptDone
|
||||
|
||||
AdaptSub: je AdaptDone
|
||||
|
||||
AdaptSubLoop:
|
||||
movq mm0, [eax]
|
||||
psubw mm0, [ecx]
|
||||
movq [eax], mm0
|
||||
movq mm1, [eax + 8]
|
||||
psubw mm1, [ecx + 8]
|
||||
movq [eax + 8], mm1
|
||||
movq mm2, [eax + 16]
|
||||
psubw mm2, [ecx + 16]
|
||||
movq [eax + 16], mm2
|
||||
movq mm3, [eax + 24]
|
||||
psubw mm3, [ecx + 24]
|
||||
movq [eax + 24], mm3
|
||||
add eax, 32
|
||||
add ecx, 32
|
||||
dec edx
|
||||
jnz AdaptSubLoop
|
||||
|
||||
emms
|
||||
AdaptDone:
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#endif /* ENABLE_ASSEMBLY */
|
||||
|
||||
if ( nDirection > 0 ) {
|
||||
nOrder >>= 4;
|
||||
while ( nOrder-- ) {
|
||||
EXPAND_16_TIMES (*pM++ += *pAdapt++;)
|
||||
}
|
||||
}
|
||||
else if ( nDirection < 0 ) {
|
||||
nOrder >>= 4;
|
||||
while ( nOrder-- ) {
|
||||
EXPAND_16_TIMES (*pM++ -= *pAdapt++;)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int CNNFilter ::
|
||||
CalculateDotProduct ( const short* pA, const short* pB, int nOrder )
|
||||
{
|
||||
int nDotProduct;
|
||||
|
||||
#ifdef ENABLE_ASSEMBLY
|
||||
|
||||
if ( m_bMMXAvailable ) {
|
||||
_asm {
|
||||
mov eax, pA
|
||||
mov ecx, pB
|
||||
mov edx, nOrder
|
||||
shr edx, 4
|
||||
pxor mm7, mm7
|
||||
|
||||
loopDot: movq mm0, [eax]
|
||||
pmaddwd mm0, [ecx]
|
||||
paddd mm7, mm0
|
||||
movq mm1, [eax + 8]
|
||||
pmaddwd mm1, [ecx + 8]
|
||||
paddd mm7, mm1
|
||||
movq mm2, [eax + 16]
|
||||
pmaddwd mm2, [ecx + 16]
|
||||
paddd mm7, mm2
|
||||
movq mm3, [eax + 24]
|
||||
pmaddwd mm3, [ecx + 24]
|
||||
add eax, 32
|
||||
add ecx, 32
|
||||
paddd mm7, mm3
|
||||
dec edx
|
||||
jnz loopDot
|
||||
|
||||
movq mm6, mm7 // mm7 has the final dot-product (split into two dwords)
|
||||
psrlq mm7, 32
|
||||
paddd mm6, mm7
|
||||
movd nDotProduct, mm6
|
||||
|
||||
emms // this emms may be unnecessary, but it's probably better to be safe...
|
||||
}
|
||||
|
||||
return nDotProduct;
|
||||
}
|
||||
|
||||
#endif /* ENABLE_ASSEMBLY */
|
||||
|
||||
nDotProduct = 0;
|
||||
nOrder >>= 4;
|
||||
|
||||
while ( nOrder-- ) {
|
||||
EXPAND_16_TIMES ( nDotProduct += *pA++ * *pB++; )
|
||||
}
|
||||
|
||||
return nDotProduct;
|
||||
}
|
||||
|
||||
#endif /* __GNUC_IA32__ */
|
||||
|
||||
/* end of NNFilter.cpp */
|
44
gst/monkeyaudio/libmonkeyaudio/NNFilter.h
Normal file
44
gst/monkeyaudio/libmonkeyaudio/NNFilter.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
#ifndef APE_NNFILTER_H
|
||||
#define APE_NNFILTER_H
|
||||
|
||||
#include "RollBuffer.h"
|
||||
#define NN_WINDOW_ELEMENTS 512
|
||||
|
||||
#ifdef __GNUC_IA32__
|
||||
extern "C" {
|
||||
__inline void Adapt ( short* pM, const short* pAdapt, int nDirection, int nOrder );
|
||||
__inline int CalculateDotProduct ( const short* pA, const short* pB, int nOrder );
|
||||
};
|
||||
#endif
|
||||
|
||||
class CNNFilter
|
||||
{
|
||||
public:
|
||||
|
||||
CNNFilter(int nOrder, int nShift);
|
||||
~CNNFilter();
|
||||
|
||||
int Compress(int nInput);
|
||||
int Decompress(int nInput);
|
||||
void Flush();
|
||||
|
||||
private:
|
||||
|
||||
int m_nOrder;
|
||||
int m_nShift;
|
||||
int m_nRoundAdd;
|
||||
BOOL m_bMMXAvailable;
|
||||
|
||||
CRollBuffer<short> m_rbInput;
|
||||
CRollBuffer<short> m_rbDeltaM;
|
||||
|
||||
short * m_paryM;
|
||||
|
||||
__inline short GetSaturatedShortFromInt ( int nValue );
|
||||
#ifndef __GNUC_IA32__
|
||||
__inline void Adapt ( short* pM, const short* pAdapt, int nDirection, int nOrder );
|
||||
__inline int CalculateDotProduct ( const short* pA, const short* pB, int nOrder );
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif /* APE_NNFILTER_H */
|
375
gst/monkeyaudio/libmonkeyaudio/NewPredictor.cpp
Normal file
375
gst/monkeyaudio/libmonkeyaudio/NewPredictor.cpp
Normal file
|
@ -0,0 +1,375 @@
|
|||
#include "All.h"
|
||||
#include "APECompress.h"
|
||||
#include "NewPredictor.h"
|
||||
|
||||
typedef struct {
|
||||
int nFilter0Length;
|
||||
int nFilter0Shift;
|
||||
int nFilter1Length;
|
||||
int nFilter1Shift;
|
||||
int nFilter2Length;
|
||||
int nFilter2Shift;
|
||||
} OrderType;
|
||||
|
||||
// pfk:
|
||||
//
|
||||
// Where does these numbers come from?
|
||||
// What are restrictions so the compressor works for every signal possible?
|
||||
// Instead of a magic CompressionLevel these 6 (or 4 numbers) should be stored in the header
|
||||
// some MMX code may also increase speed for fast or normal compression, but reduces readability.
|
||||
// Also note that shifting is extremly slow on Pentium 4 (why? no idea!)
|
||||
// Rotation + Order of the follwoing buffers mirroring: m_rbPredictionA, m_rbPredictionB, m_rbAdaptA, m_rbAdaptB -> allows MMX/Altivec
|
||||
|
||||
const OrderType OrderTypeArray [] = {
|
||||
{ 0, 0, 0, 0, 0, 0 },
|
||||
{ 0, 0, 0, 0, 0, 0 },
|
||||
{ 16, 11, 0, 0, 0, 0 },
|
||||
{ 64, 11, 0, 0, 0, 0 },
|
||||
{ 256, 13, 32, 10, 0, 0 },
|
||||
{ 1024, 15, 256, 13, 0, 0 },
|
||||
{ 1024, 15, 256, 13, 16, 11 },
|
||||
};
|
||||
|
||||
/*****************************************************************************************
|
||||
CPredictorCompressNormal
|
||||
*****************************************************************************************/
|
||||
CPredictorCompressNormal::CPredictorCompressNormal(int nCompressionLevel)
|
||||
: IPredictorCompress(nCompressionLevel)
|
||||
{
|
||||
const OrderType* p = OrderTypeArray + nCompressionLevel / 1000;
|
||||
|
||||
if ( nCompressionLevel < 1000 || nCompressionLevel > 6000 || nCompressionLevel % 1000 != 0 )
|
||||
throw (1);
|
||||
|
||||
m_pNNFilter0 = p->nFilter0Length ? new CNNFilter (p->nFilter0Length, p->nFilter0Shift) : NULL;
|
||||
m_pNNFilter1 = p->nFilter1Length ? new CNNFilter (p->nFilter1Length, p->nFilter1Shift) : NULL;
|
||||
m_pNNFilter2 = p->nFilter2Length ? new CNNFilter (p->nFilter2Length, p->nFilter2Shift) : NULL;
|
||||
}
|
||||
|
||||
CPredictorCompressNormal::~CPredictorCompressNormal()
|
||||
{
|
||||
SAFE_DELETE (m_pNNFilter0)
|
||||
SAFE_DELETE (m_pNNFilter1)
|
||||
SAFE_DELETE (m_pNNFilter2)
|
||||
}
|
||||
|
||||
int CPredictorCompressNormal::Flush()
|
||||
{
|
||||
if ( m_pNNFilter0 != NULL ) m_pNNFilter0->Flush();
|
||||
if ( m_pNNFilter1 != NULL ) m_pNNFilter1->Flush();
|
||||
if ( m_pNNFilter2 != NULL ) m_pNNFilter2->Flush();
|
||||
|
||||
m_rbPredictionA.Flush(); m_rbPredictionB.Flush();
|
||||
m_rbAdaptA .Flush(); m_rbAdaptB .Flush();
|
||||
m_Stage1FilterA.Flush(); m_Stage1FilterB.Flush();
|
||||
|
||||
ZeroMemory(m_aryMA, sizeof(m_aryMA));
|
||||
ZeroMemory(m_aryMB, sizeof(m_aryMB));
|
||||
|
||||
m_aryMA[0] = 360;
|
||||
m_aryMA[1] = 317;
|
||||
m_aryMA[2] = -109;
|
||||
m_aryMA[3] = 98;
|
||||
|
||||
m_nLastValueA = 0;
|
||||
|
||||
m_nCurrentIndex = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int CPredictorCompressNormal::CompressValue(int nA, int nB)
|
||||
{
|
||||
if (m_nCurrentIndex == WINDOW_BLOCKS)
|
||||
{
|
||||
m_rbPredictionA.Roll(); m_rbPredictionB.Roll();
|
||||
m_rbAdaptA .Roll(); m_rbAdaptB .Roll();
|
||||
|
||||
m_nCurrentIndex = 0;
|
||||
}
|
||||
|
||||
// stage 1: simple, non-adaptive order 1 prediction
|
||||
int nCurrentA = m_Stage1FilterA.Compress(nA);
|
||||
int nCurrentB = m_Stage1FilterB.Compress(nB);
|
||||
|
||||
// stage 2: adaptive offset filter(s)
|
||||
m_rbPredictionA[0] = m_nLastValueA;
|
||||
m_rbPredictionA[-1] = m_rbPredictionA[0] - m_rbPredictionA[-1];
|
||||
|
||||
m_rbPredictionB[0] = nCurrentB;
|
||||
m_rbPredictionB[-1] = m_rbPredictionB[0] - m_rbPredictionB[-1];
|
||||
|
||||
int nPredictionA = (m_rbPredictionA[0] * m_aryMA[0]) + (m_rbPredictionA[-1] * m_aryMA[1]) + (m_rbPredictionA[-2] * m_aryMA[2]) + (m_rbPredictionA[-3] * m_aryMA[3]);
|
||||
int nPredictionB = (m_rbPredictionB[0] * m_aryMB[0]) + (m_rbPredictionB[-1] * m_aryMB[1]) + (m_rbPredictionB[-2] * m_aryMB[2]) + (m_rbPredictionB[-3] * m_aryMB[3]) + (m_rbPredictionB[-4] * m_aryMB[4]);
|
||||
|
||||
int nOutput = nCurrentA - ((nPredictionA + (nPredictionB >> 1)) >> 10);
|
||||
|
||||
m_nLastValueA = nCurrentA;
|
||||
|
||||
m_rbAdaptA[0] = (m_rbPredictionA[0]) ? ((m_rbPredictionA[0] >> 30) & 2) - 1 : 0;
|
||||
m_rbAdaptA[-1] = (m_rbPredictionA[-1]) ? ((m_rbPredictionA[-1] >> 30) & 2) - 1 : 0;
|
||||
|
||||
m_rbAdaptB[0] = (m_rbPredictionB[0]) ? ((m_rbPredictionB[0] >> 30) & 2) - 1 : 0;
|
||||
m_rbAdaptB[-1] = (m_rbPredictionB[-1]) ? ((m_rbPredictionB[-1] >> 30) & 2) - 1 : 0;
|
||||
|
||||
if (nOutput > 0)
|
||||
{
|
||||
m_aryMA[0] -= m_rbAdaptA[0];
|
||||
m_aryMA[1] -= m_rbAdaptA[-1];
|
||||
m_aryMA[2] -= m_rbAdaptA[-2];
|
||||
m_aryMA[3] -= m_rbAdaptA[-3];
|
||||
|
||||
m_aryMB[0] -= m_rbAdaptB[0];
|
||||
m_aryMB[1] -= m_rbAdaptB[-1];
|
||||
m_aryMB[2] -= m_rbAdaptB[-2];
|
||||
m_aryMB[3] -= m_rbAdaptB[-3];
|
||||
m_aryMB[4] -= m_rbAdaptB[-4];
|
||||
}
|
||||
else if (nOutput < 0)
|
||||
{
|
||||
m_aryMA[0] += m_rbAdaptA[0];
|
||||
m_aryMA[1] += m_rbAdaptA[-1];
|
||||
m_aryMA[2] += m_rbAdaptA[-2];
|
||||
m_aryMA[3] += m_rbAdaptA[-3];
|
||||
|
||||
m_aryMB[0] += m_rbAdaptB[0];
|
||||
m_aryMB[1] += m_rbAdaptB[-1];
|
||||
m_aryMB[2] += m_rbAdaptB[-2];
|
||||
m_aryMB[3] += m_rbAdaptB[-3];
|
||||
m_aryMB[4] += m_rbAdaptB[-4];
|
||||
}
|
||||
|
||||
// stage 3: NNFilters
|
||||
|
||||
if ( m_pNNFilter0 != NULL ) nOutput = m_pNNFilter0->Compress(nOutput);
|
||||
if ( m_pNNFilter1 != NULL ) nOutput = m_pNNFilter1->Compress(nOutput);
|
||||
if ( m_pNNFilter2 != NULL ) nOutput = m_pNNFilter2->Compress(nOutput);
|
||||
|
||||
m_rbPredictionA.IncrementFast(); m_rbPredictionB.IncrementFast();
|
||||
m_rbAdaptA.IncrementFast(); m_rbAdaptB.IncrementFast();
|
||||
|
||||
m_nCurrentIndex++;
|
||||
|
||||
return nOutput;
|
||||
}
|
||||
|
||||
/*****************************************************************************************
|
||||
CPredictorDecompressNormal3930to3950
|
||||
*****************************************************************************************/
|
||||
CPredictorDecompressNormal3930to3950::CPredictorDecompressNormal3930to3950(int nCompressionLevel)
|
||||
: IPredictorDecompress(nCompressionLevel)
|
||||
{
|
||||
const OrderType* p = OrderTypeArray + nCompressionLevel / 1000;
|
||||
m_pBuffer[0] = new int [HISTORY_ELEMENTS + WINDOW_BLOCKS];
|
||||
|
||||
if ( nCompressionLevel < 1000 || nCompressionLevel > 6000 || nCompressionLevel % 1000 != 0 )
|
||||
throw (1);
|
||||
|
||||
m_pNNFilter0 = p->nFilter0Length ? new CNNFilter (p->nFilter0Length, p->nFilter0Shift) : NULL;
|
||||
m_pNNFilter1 = p->nFilter1Length ? new CNNFilter (p->nFilter1Length, p->nFilter1Shift) : NULL;
|
||||
m_pNNFilter2 = p->nFilter2Length ? new CNNFilter (p->nFilter2Length, p->nFilter2Shift) : NULL;
|
||||
}
|
||||
|
||||
CPredictorDecompressNormal3930to3950::~CPredictorDecompressNormal3930to3950()
|
||||
{
|
||||
SAFE_DELETE (m_pNNFilter0)
|
||||
SAFE_DELETE (m_pNNFilter1)
|
||||
SAFE_DELETE (m_pNNFilter2)
|
||||
SAFE_ARRAY_DELETE(m_pBuffer[0])
|
||||
}
|
||||
|
||||
int CPredictorDecompressNormal3930to3950::Flush()
|
||||
{
|
||||
if (m_pNNFilter0) m_pNNFilter0->Flush();
|
||||
if (m_pNNFilter1) m_pNNFilter1->Flush();
|
||||
if (m_pNNFilter2) m_pNNFilter2->Flush();
|
||||
|
||||
ZeroMemory(m_pBuffer[0], (HISTORY_ELEMENTS + 1) * sizeof(int));
|
||||
ZeroMemory(&m_aryM[0], M_COUNT * sizeof(int));
|
||||
|
||||
m_aryM[0] = 360;
|
||||
m_aryM[1] = 317;
|
||||
m_aryM[2] = -109;
|
||||
m_aryM[3] = 98;
|
||||
|
||||
m_pInputBuffer = &m_pBuffer[0][HISTORY_ELEMENTS];
|
||||
|
||||
m_nLastValue = 0;
|
||||
m_nCurrentIndex = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CPredictorDecompressNormal3930to3950::DecompressValue(int nInput, int)
|
||||
{
|
||||
if (m_nCurrentIndex == WINDOW_BLOCKS)
|
||||
{
|
||||
// copy forward and adjust pointers
|
||||
memcpy(&m_pBuffer[0][0], &m_pBuffer[0][WINDOW_BLOCKS], HISTORY_ELEMENTS * sizeof(int));
|
||||
m_pInputBuffer = &m_pBuffer[0][HISTORY_ELEMENTS];
|
||||
|
||||
m_nCurrentIndex = 0;
|
||||
}
|
||||
|
||||
// stage 2: NNFilter
|
||||
if (m_pNNFilter2 != NULL) nInput = m_pNNFilter2->Decompress(nInput);
|
||||
if (m_pNNFilter1 != NULL) nInput = m_pNNFilter1->Decompress(nInput);
|
||||
if (m_pNNFilter0 != NULL) nInput = m_pNNFilter0->Decompress(nInput);
|
||||
|
||||
// stage 1: multiple predictors (order 2 and offset 1)
|
||||
|
||||
int p1 = m_pInputBuffer[-1];
|
||||
int p2 = m_pInputBuffer[-1] - m_pInputBuffer[-2];
|
||||
int p3 = m_pInputBuffer[-2] - m_pInputBuffer[-3];
|
||||
int p4 = m_pInputBuffer[-3] - m_pInputBuffer[-4];
|
||||
|
||||
m_pInputBuffer[0] = nInput + ((p1 * m_aryM[0] + p2 * m_aryM[1] + p3 * m_aryM[2] + p4 * m_aryM[3]) >> 9);
|
||||
|
||||
if (nInput > 0)
|
||||
{
|
||||
m_aryM[0] -= ((p1 >> 30) & 2) - 1;
|
||||
m_aryM[1] -= ((p2 >> 30) & 2) - 1;
|
||||
m_aryM[2] -= ((p3 >> 30) & 2) - 1;
|
||||
m_aryM[3] -= ((p4 >> 30) & 2) - 1;
|
||||
}
|
||||
else if (nInput < 0)
|
||||
{
|
||||
m_aryM[0] += ((p1 >> 30) & 2) - 1;
|
||||
m_aryM[1] += ((p2 >> 30) & 2) - 1;
|
||||
m_aryM[2] += ((p3 >> 30) & 2) - 1;
|
||||
m_aryM[3] += ((p4 >> 30) & 2) - 1;
|
||||
}
|
||||
|
||||
int nRetVal = m_pInputBuffer[0] + ((m_nLastValue * 31) >> 5);
|
||||
m_nLastValue = nRetVal;
|
||||
|
||||
m_nCurrentIndex++;
|
||||
m_pInputBuffer++;
|
||||
|
||||
return nRetVal;
|
||||
}
|
||||
|
||||
/*****************************************************************************************
|
||||
CPredictorDecompress3950toCurrent
|
||||
*****************************************************************************************/
|
||||
CPredictorDecompress3950toCurrent::CPredictorDecompress3950toCurrent(int nCompressionLevel)
|
||||
: IPredictorDecompress(nCompressionLevel)
|
||||
{
|
||||
const OrderType* p = OrderTypeArray + nCompressionLevel / 1000;
|
||||
|
||||
if ( nCompressionLevel < 1000 || nCompressionLevel > 6000 || nCompressionLevel % 1000 != 0 )
|
||||
throw (1);
|
||||
|
||||
m_pNNFilter0 = p->nFilter0Length ? new CNNFilter (p->nFilter0Length, p->nFilter0Shift) : NULL;
|
||||
m_pNNFilter1 = p->nFilter1Length ? new CNNFilter (p->nFilter1Length, p->nFilter1Shift) : NULL;
|
||||
m_pNNFilter2 = p->nFilter2Length ? new CNNFilter (p->nFilter2Length, p->nFilter2Shift) : NULL;
|
||||
}
|
||||
|
||||
CPredictorDecompress3950toCurrent::~CPredictorDecompress3950toCurrent()
|
||||
{
|
||||
SAFE_DELETE(m_pNNFilter0)
|
||||
SAFE_DELETE(m_pNNFilter1)
|
||||
SAFE_DELETE(m_pNNFilter2)
|
||||
}
|
||||
|
||||
int CPredictorDecompress3950toCurrent::Flush()
|
||||
{
|
||||
if (m_pNNFilter0 != NULL) m_pNNFilter0->Flush();
|
||||
if (m_pNNFilter1 != NULL) m_pNNFilter1->Flush();
|
||||
if (m_pNNFilter2 != NULL) m_pNNFilter2->Flush();
|
||||
|
||||
ZeroMemory(m_aryMA, sizeof(m_aryMA));
|
||||
ZeroMemory(m_aryMB, sizeof(m_aryMB));
|
||||
|
||||
m_rbPredictionA.Flush();
|
||||
m_rbPredictionB.Flush();
|
||||
m_rbAdaptA.Flush();
|
||||
m_rbAdaptB.Flush();
|
||||
|
||||
m_aryMA[0] = 360;
|
||||
m_aryMA[1] = 317;
|
||||
m_aryMA[2] = -109;
|
||||
m_aryMA[3] = 98;
|
||||
|
||||
m_Stage1FilterA.Flush();
|
||||
m_Stage1FilterB.Flush();
|
||||
|
||||
m_nLastValueA = 0;
|
||||
|
||||
m_nCurrentIndex = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CPredictorDecompress3950toCurrent::DecompressValue(int nA, int nB)
|
||||
{
|
||||
if (m_nCurrentIndex == WINDOW_BLOCKS)
|
||||
{
|
||||
// copy forward and adjust pointers
|
||||
m_rbPredictionA.Roll(); m_rbPredictionB.Roll();
|
||||
m_rbAdaptA.Roll(); m_rbAdaptB.Roll();
|
||||
|
||||
m_nCurrentIndex = 0;
|
||||
}
|
||||
|
||||
// stage 2: NNFilter
|
||||
if (m_pNNFilter2 != NULL) nA = m_pNNFilter2->Decompress(nA);
|
||||
if (m_pNNFilter1 != NULL) nA = m_pNNFilter1->Decompress(nA);
|
||||
if (m_pNNFilter0 != NULL) nA = m_pNNFilter0->Decompress(nA);
|
||||
|
||||
// stage 1: multiple predictors (order 2 and offset 1)
|
||||
m_rbPredictionA[0] = m_nLastValueA;
|
||||
m_rbPredictionA[-1] = m_rbPredictionA[0] - m_rbPredictionA[-1];
|
||||
|
||||
m_rbPredictionB[0] = m_Stage1FilterB.Compress(nB);
|
||||
m_rbPredictionB[-1] = m_rbPredictionB[0] - m_rbPredictionB[-1];
|
||||
|
||||
int nPredictionA = (m_rbPredictionA[0] * m_aryMA[0]) + (m_rbPredictionA[-1] * m_aryMA[1]) + (m_rbPredictionA[-2] * m_aryMA[2]) + (m_rbPredictionA[-3] * m_aryMA[3]);
|
||||
int nPredictionB = (m_rbPredictionB[0] * m_aryMB[0]) + (m_rbPredictionB[-1] * m_aryMB[1]) + (m_rbPredictionB[-2] * m_aryMB[2]) + (m_rbPredictionB[-3] * m_aryMB[3]) + (m_rbPredictionB[-4] * m_aryMB[4]);
|
||||
|
||||
int nCurrentA = nA + ((nPredictionA + (nPredictionB >> 1)) >> 10);
|
||||
|
||||
m_rbAdaptA[0] = (m_rbPredictionA[0]) ? ((m_rbPredictionA[0] >> 30) & 2) - 1 : 0;
|
||||
m_rbAdaptA[-1] = (m_rbPredictionA[-1]) ? ((m_rbPredictionA[-1] >> 30) & 2) - 1 : 0;
|
||||
|
||||
m_rbAdaptB[0] = (m_rbPredictionB[0]) ? ((m_rbPredictionB[0] >> 30) & 2) - 1 : 0;
|
||||
m_rbAdaptB[-1] = (m_rbPredictionB[-1]) ? ((m_rbPredictionB[-1] >> 30) & 2) - 1 : 0;
|
||||
|
||||
if (nA > 0)
|
||||
{
|
||||
m_aryMA[0] -= m_rbAdaptA[0];
|
||||
m_aryMA[1] -= m_rbAdaptA[-1];
|
||||
m_aryMA[2] -= m_rbAdaptA[-2];
|
||||
m_aryMA[3] -= m_rbAdaptA[-3];
|
||||
|
||||
m_aryMB[0] -= m_rbAdaptB[0];
|
||||
m_aryMB[1] -= m_rbAdaptB[-1];
|
||||
m_aryMB[2] -= m_rbAdaptB[-2];
|
||||
m_aryMB[3] -= m_rbAdaptB[-3];
|
||||
m_aryMB[4] -= m_rbAdaptB[-4];
|
||||
}
|
||||
else if (nA < 0)
|
||||
{
|
||||
m_aryMA[0] += m_rbAdaptA[0];
|
||||
m_aryMA[1] += m_rbAdaptA[-1];
|
||||
m_aryMA[2] += m_rbAdaptA[-2];
|
||||
m_aryMA[3] += m_rbAdaptA[-3];
|
||||
|
||||
m_aryMB[0] += m_rbAdaptB[0];
|
||||
m_aryMB[1] += m_rbAdaptB[-1];
|
||||
m_aryMB[2] += m_rbAdaptB[-2];
|
||||
m_aryMB[3] += m_rbAdaptB[-3];
|
||||
m_aryMB[4] += m_rbAdaptB[-4];
|
||||
}
|
||||
|
||||
int nRetVal = m_Stage1FilterA.Decompress(nCurrentA);
|
||||
m_nLastValueA = nCurrentA;
|
||||
|
||||
m_rbPredictionA.IncrementFast(); m_rbPredictionB.IncrementFast();
|
||||
m_rbAdaptA.IncrementFast(); m_rbAdaptB.IncrementFast();
|
||||
|
||||
m_nCurrentIndex++;
|
||||
|
||||
return nRetVal;
|
||||
}
|
124
gst/monkeyaudio/libmonkeyaudio/NewPredictor.h
Normal file
124
gst/monkeyaudio/libmonkeyaudio/NewPredictor.h
Normal file
|
@ -0,0 +1,124 @@
|
|||
#ifndef APE_NEWPREDICTOR_H
|
||||
#define APE_NEWPREDICTOR_H
|
||||
|
||||
#include "Predictor.h"
|
||||
|
||||
#include "RollBuffer.h"
|
||||
#include "NNFilter.h"
|
||||
#include "ScaledFirstOrderFilter.h"
|
||||
|
||||
/*************************************************************************************************
|
||||
Functions to create the interfaces
|
||||
*************************************************************************************************/
|
||||
IPredictorCompress * __stdcall CreateIPredictorCompress();
|
||||
IPredictorDecompress * __stdcall CreateIPredictorDecompress();
|
||||
|
||||
#define WINDOW_BLOCKS 512
|
||||
|
||||
#define BUFFER_COUNT 1
|
||||
#define HISTORY_ELEMENTS 8
|
||||
#define M_COUNT 8
|
||||
|
||||
class CPredictorCompressNormal : public IPredictorCompress
|
||||
{
|
||||
public:
|
||||
CPredictorCompressNormal(int nCompressionLevel);
|
||||
virtual ~CPredictorCompressNormal();
|
||||
|
||||
int CompressValue(int nA, int nB = 0);
|
||||
int Flush();
|
||||
|
||||
protected:
|
||||
|
||||
// buffer information
|
||||
// CRollBuffer<int> m_rbBufferA;
|
||||
// CRollBuffer<int> m_rbBufferB;
|
||||
|
||||
CRollBufferFast<int, WINDOW_BLOCKS, 8> m_rbPredictionA;
|
||||
CRollBufferFast<int, WINDOW_BLOCKS, 8> m_rbPredictionB;
|
||||
|
||||
CRollBufferFast<int, WINDOW_BLOCKS, 8> m_rbAdaptA;
|
||||
CRollBufferFast<int, WINDOW_BLOCKS, 8> m_rbAdaptB;
|
||||
|
||||
CScaledFirstOrderFilter<31, 5> m_Stage1FilterA;
|
||||
CScaledFirstOrderFilter<31, 5> m_Stage1FilterB;
|
||||
|
||||
// adaption
|
||||
int m_aryMA[M_COUNT];
|
||||
int m_aryMB[M_COUNT];
|
||||
|
||||
// other
|
||||
int m_nCurrentIndex;
|
||||
int m_nLastValueA;
|
||||
// int m_nLastValueB;
|
||||
CNNFilter * m_pNNFilter0;
|
||||
CNNFilter * m_pNNFilter1;
|
||||
CNNFilter * m_pNNFilter2;
|
||||
|
||||
// BOOL m_bFirst;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class CPredictorDecompressNormal3930to3950 : public IPredictorDecompress
|
||||
{
|
||||
public:
|
||||
CPredictorDecompressNormal3930to3950(int nCompressionLevel);
|
||||
virtual ~CPredictorDecompressNormal3930to3950();
|
||||
|
||||
int DecompressValue(int nInput, int);
|
||||
int Flush();
|
||||
|
||||
protected:
|
||||
|
||||
// buffer information
|
||||
int * m_pBuffer[BUFFER_COUNT];
|
||||
|
||||
// adaption
|
||||
int m_aryM[M_COUNT];
|
||||
|
||||
// buffer pointers
|
||||
int * m_pInputBuffer;
|
||||
|
||||
// other
|
||||
int m_nCurrentIndex;
|
||||
int m_nLastValue;
|
||||
CNNFilter * m_pNNFilter0;
|
||||
CNNFilter * m_pNNFilter1;
|
||||
CNNFilter * m_pNNFilter2;
|
||||
};
|
||||
|
||||
class CPredictorDecompress3950toCurrent : public IPredictorDecompress
|
||||
{
|
||||
public:
|
||||
CPredictorDecompress3950toCurrent(int nCompressionLevel);
|
||||
virtual ~CPredictorDecompress3950toCurrent();
|
||||
|
||||
int DecompressValue(int nA, int nB = 0);
|
||||
int Flush();
|
||||
|
||||
protected:
|
||||
|
||||
// adaption
|
||||
int m_aryMA[M_COUNT];
|
||||
int m_aryMB[M_COUNT];
|
||||
|
||||
// buffer pointers
|
||||
CRollBufferFast<int, WINDOW_BLOCKS, 8> m_rbPredictionA;
|
||||
CRollBufferFast<int, WINDOW_BLOCKS, 8> m_rbPredictionB;
|
||||
|
||||
CRollBufferFast<int, WINDOW_BLOCKS, 8> m_rbAdaptA;
|
||||
CRollBufferFast<int, WINDOW_BLOCKS, 8> m_rbAdaptB;
|
||||
|
||||
CScaledFirstOrderFilter<31, 5> m_Stage1FilterA;
|
||||
CScaledFirstOrderFilter<31, 5> m_Stage1FilterB;
|
||||
|
||||
// other
|
||||
int m_nCurrentIndex;
|
||||
int m_nLastValueA;
|
||||
CNNFilter * m_pNNFilter0;
|
||||
CNNFilter * m_pNNFilter1;
|
||||
CNNFilter * m_pNNFilter2;
|
||||
};
|
||||
|
||||
#endif /* APE_NEWPREDICTOR_H */
|
69
gst/monkeyaudio/libmonkeyaudio/NoWindows.h
Normal file
69
gst/monkeyaudio/libmonkeyaudio/NoWindows.h
Normal file
|
@ -0,0 +1,69 @@
|
|||
#ifndef APE_NOWINDOWS_H
|
||||
#define APE_NOWINDOWS_H
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
#define NEAR
|
||||
#define FAR
|
||||
|
||||
#define __int64 long long
|
||||
#define __int32 int
|
||||
#define __int16 short
|
||||
#define __int8 char
|
||||
|
||||
typedef unsigned long DWORD;
|
||||
typedef int BOOL;
|
||||
typedef unsigned char BYTE;
|
||||
typedef unsigned short WORD;
|
||||
typedef float FLOAT;
|
||||
typedef void * HANDLE;
|
||||
typedef unsigned int UINT;
|
||||
typedef unsigned int WPARAM;
|
||||
typedef long LPARAM;
|
||||
typedef const char * LPCSTR;
|
||||
typedef char * LPSTR;
|
||||
typedef long LRESULT;
|
||||
|
||||
#define ZeroMemory(POINTER, BYTES) memset(POINTER, 0, BYTES);
|
||||
#define max(a,b) (((a) > (b)) ? (a) : (b))
|
||||
#define min(a,b) (((a) < (b)) ? (a) : (b))
|
||||
|
||||
#define __stdcall
|
||||
#define CALLBACK
|
||||
|
||||
#define _stricmp strcasecmp
|
||||
#define _strnicmp strncasecmp
|
||||
|
||||
#define _FPOSOFF(fp) ((long)(fp).__pos)
|
||||
#define MAX_PATH 4096
|
||||
|
||||
#ifndef _WAVEFORMATEX_
|
||||
#define _WAVEFORMATEX_
|
||||
|
||||
typedef struct tWAVEFORMATEX
|
||||
{
|
||||
WORD wFormatTag; /* format type */
|
||||
WORD nChannels; /* number of channels (i.e. mono, stereo...) */
|
||||
DWORD nSamplesPerSec; /* sample rate */
|
||||
DWORD nAvgBytesPerSec; /* for buffer estimation */
|
||||
WORD nBlockAlign; /* block size of data */
|
||||
WORD wBitsPerSample; /* number of bits per sample of mono data */
|
||||
WORD cbSize; /* the count in bytes of the size of */
|
||||
/* extra information (after cbSize) */
|
||||
} WAVEFORMATEX, *PWAVEFORMATEX, NEAR *NPWAVEFORMATEX, FAR *LPWAVEFORMATEX;
|
||||
|
||||
typedef const WAVEFORMATEX FAR *LPCWAVEFORMATEX;
|
||||
|
||||
#endif // #ifndef _WAVEFORMATEX_
|
||||
|
||||
#endif // #ifndef _WIN32
|
||||
|
||||
#endif /* APE_NOWINDOWS_H */
|
30
gst/monkeyaudio/libmonkeyaudio/Predictor.h
Normal file
30
gst/monkeyaudio/libmonkeyaudio/Predictor.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
#ifndef APE_PREDICTOR_H
|
||||
#define APE_PREDICTOR_H
|
||||
|
||||
/*************************************************************************************************
|
||||
IPredictorCompress - the interface for compressing (predicting) data
|
||||
*************************************************************************************************/
|
||||
class IPredictorCompress
|
||||
{
|
||||
public:
|
||||
IPredictorCompress(int nCompressionLevel) {}
|
||||
virtual ~IPredictorCompress() {}
|
||||
|
||||
virtual int CompressValue(int nA, int nB = 0) = 0;
|
||||
virtual int Flush() = 0;
|
||||
};
|
||||
|
||||
/*************************************************************************************************
|
||||
IPredictorDecompress - the interface for decompressing (un-predicting) data
|
||||
*************************************************************************************************/
|
||||
class IPredictorDecompress
|
||||
{
|
||||
public:
|
||||
IPredictorDecompress(int nCompressionLevel) {}
|
||||
virtual ~IPredictorDecompress() {}
|
||||
|
||||
virtual int DecompressValue(int nA, int nB = 0) = 0;
|
||||
virtual int Flush() = 0;
|
||||
};
|
||||
|
||||
#endif /* APE_PREDICTOR_H */
|
517
gst/monkeyaudio/libmonkeyaudio/Prepare.cpp
Normal file
517
gst/monkeyaudio/libmonkeyaudio/Prepare.cpp
Normal file
|
@ -0,0 +1,517 @@
|
|||
#include "All.h"
|
||||
#include "Prepare.h"
|
||||
|
||||
const unsigned __int32 CRC32_Table[256] = {0LU,1996959894LU,3993919788LU,2567524794LU,124634137LU,1886057615LU,3915621685LU,2657392035LU,249268274LU,2044508324LU,3772115230LU,2547177864LU,162941995LU,2125561021LU,3887607047LU,2428444049LU,498536548LU,1789927666LU,4089016648LU,2227061214LU,450548861LU,1843258603LU,4107580753LU,2211677639LU,325883990LU,1684777152LU,4251122042LU,2321926636LU,335633487LU,1661365465LU,4195302755LU,2366115317LU,997073096LU,1281953886LU,3579855332LU,2724688242LU,1006888145LU,1258607687LU,3524101629LU,2768942443LU,901097722LU,1119000684LU,3686517206LU,2898065728LU,853044451LU,1172266101LU,3705015759LU,2882616665LU,651767980LU,1373503546LU,3369554304LU,3218104598LU,565507253LU,1454621731LU,3485111705LU,3099436303LU,671266974LU,1594198024LU,3322730930LU,2970347812LU,795835527LU,1483230225LU,3244367275LU,3060149565LU,1994146192LU,31158534LU,2563907772LU,4023717930LU,1907459465LU,112637215LU,2680153253LU,3904427059LU,2013776290LU,251722036LU,2517215374LU,3775830040LU,2137656763LU,141376813LU,2439277719LU,3865271297LU,1802195444LU,476864866LU,2238001368LU,
|
||||
4066508878LU,1812370925LU,453092731LU,2181625025LU,4111451223LU,1706088902LU,314042704LU,2344532202LU,4240017532LU,1658658271LU,366619977LU,2362670323LU,4224994405LU,1303535960LU,984961486LU,2747007092LU,3569037538LU,1256170817LU,1037604311LU,2765210733LU,3554079995LU,1131014506LU,879679996LU,2909243462LU,3663771856LU,1141124467LU,855842277LU,2852801631LU,3708648649LU,1342533948LU,654459306LU,3188396048LU,3373015174LU,1466479909LU,544179635LU,3110523913LU,3462522015LU,1591671054LU,702138776LU,2966460450LU,3352799412LU,1504918807LU,783551873LU,3082640443LU,3233442989LU,3988292384LU,2596254646LU,62317068LU,1957810842LU,3939845945LU,2647816111LU,81470997LU,1943803523LU,3814918930LU,2489596804LU,225274430LU,2053790376LU,3826175755LU,2466906013LU,167816743LU,2097651377LU,4027552580LU,2265490386LU,503444072LU,1762050814LU,4150417245LU,2154129355LU,426522225LU,1852507879LU,4275313526LU,2312317920LU,282753626LU,1742555852LU,4189708143LU,2394877945LU,397917763LU,1622183637LU,3604390888LU,2714866558LU,953729732LU,1340076626LU,3518719985LU,2797360999LU,1068828381LU,1219638859LU,3624741850LU,
|
||||
2936675148LU,906185462LU,1090812512LU,3747672003LU,2825379669LU,829329135LU,1181335161LU,3412177804LU,3160834842LU,628085408LU,1382605366LU,3423369109LU,3138078467LU,570562233LU,1426400815LU,3317316542LU,2998733608LU,733239954LU,1555261956LU,3268935591LU,3050360625LU,752459403LU,1541320221LU,2607071920LU,3965973030LU,1969922972LU,40735498LU,2617837225LU,3943577151LU,1913087877LU,83908371LU,2512341634LU,3803740692LU,2075208622LU,213261112LU,2463272603LU,3855990285LU,2094854071LU,198958881LU,2262029012LU,4057260610LU,1759359992LU,534414190LU,2176718541LU,4139329115LU,1873836001LU,414664567LU,2282248934LU,4279200368LU,1711684554LU,285281116LU,2405801727LU,4167216745LU,1634467795LU,376229701LU,2685067896LU,3608007406LU,1308918612LU,956543938LU,2808555105LU,3495958263LU,1231636301LU,1047427035LU,2932959818LU,3654703836LU,1088359270LU,936918000LU,2847714899LU,3736837829LU,1202900863LU,817233897LU,3183342108LU,3401237130LU,1404277552LU,615818150LU,3134207493LU,3453421203LU,1423857449LU,601450431LU,3009837614LU,3294710456LU,1567103746LU,711928724LU,3020668471LU,3272380065LU,1510334235LU,755167117LU};
|
||||
|
||||
/*
|
||||
if (nR > 32767) nR = 32767;
|
||||
else if (nR < -32768) nR = -32768;
|
||||
if (nL > 32767) nL = 32767;
|
||||
else if (nL < -32768) nL = -32768;
|
||||
*/
|
||||
|
||||
int CPrepare::Prepare(unsigned char * pRawData, int nBytes, const WAVEFORMATEX * pWaveFormatEx, int * pOutputX, int *pOutputY, unsigned int *pCRC, int *pSpecialCodes, int *pPeakLevel)
|
||||
{
|
||||
// error check the parameters
|
||||
if (pRawData == NULL || pWaveFormatEx == NULL)
|
||||
return ERROR_BAD_PARAMETER;
|
||||
|
||||
// initialize the pointers that got passed in
|
||||
*pCRC = 0xFFFFFFFF;
|
||||
*pSpecialCodes = 0;
|
||||
|
||||
// variables
|
||||
unsigned __int32 CRC = 0xFFFFFFFF;
|
||||
const int nTotalBlocks = nBytes / pWaveFormatEx->nBlockAlign;
|
||||
int R,L;
|
||||
|
||||
// the prepare code
|
||||
|
||||
if (pWaveFormatEx->wBitsPerSample == 8)
|
||||
{
|
||||
if (pWaveFormatEx->nChannels == 2)
|
||||
{
|
||||
for (int nBlockIndex = 0; nBlockIndex < nTotalBlocks; nBlockIndex++)
|
||||
{
|
||||
R = (int) (*((unsigned char *) pRawData) - 128);
|
||||
L = (int) (*((unsigned char *) (pRawData + 1)) - 128);
|
||||
|
||||
CRC = (CRC >> 8) ^ CRC32_Table[(CRC & 0xFF) ^ *pRawData++];
|
||||
CRC = (CRC >> 8) ^ CRC32_Table[(CRC & 0xFF) ^ *pRawData++];
|
||||
|
||||
// check the peak
|
||||
if (labs(L) > *pPeakLevel)
|
||||
*pPeakLevel = labs(L);
|
||||
if (labs(R) > *pPeakLevel)
|
||||
*pPeakLevel = labs(R);
|
||||
|
||||
// convert to x,y
|
||||
pOutputY[nBlockIndex] = L - R;
|
||||
pOutputX[nBlockIndex] = R + (pOutputY[nBlockIndex] / 2);
|
||||
}
|
||||
}
|
||||
else if (pWaveFormatEx->nChannels == 1)
|
||||
{
|
||||
for (int nBlockIndex = 0; nBlockIndex < nTotalBlocks; nBlockIndex++)
|
||||
{
|
||||
R = (int) (*((unsigned char *) pRawData) - 128);
|
||||
|
||||
CRC = (CRC >> 8) ^ CRC32_Table[(CRC & 0xFF) ^ *pRawData++];
|
||||
|
||||
// check the peak
|
||||
if (labs(R) > *pPeakLevel)
|
||||
*pPeakLevel = labs(R);
|
||||
|
||||
// convert to x,y
|
||||
pOutputX[nBlockIndex] = R;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (pWaveFormatEx->wBitsPerSample == 24)
|
||||
{
|
||||
if (pWaveFormatEx->nChannels == 2)
|
||||
{
|
||||
for (int nBlockIndex = 0; nBlockIndex < nTotalBlocks; nBlockIndex++)
|
||||
{
|
||||
unsigned __int32 nTemp = 0;
|
||||
|
||||
nTemp |= (*pRawData << 0);
|
||||
CRC = (CRC >> 8) ^ CRC32_Table[(CRC & 0xFF) ^ *pRawData++];
|
||||
|
||||
nTemp |= (*pRawData << 8);
|
||||
CRC = (CRC >> 8) ^ CRC32_Table[(CRC & 0xFF) ^ *pRawData++];
|
||||
|
||||
nTemp |= (*pRawData << 16);
|
||||
CRC = (CRC >> 8) ^ CRC32_Table[(CRC & 0xFF) ^ *pRawData++];
|
||||
|
||||
if (nTemp & 0x800000)
|
||||
R = (int) (nTemp & 0x7fffff) - 0x800000;
|
||||
else
|
||||
R = (int) (nTemp & 0x7fffff);
|
||||
|
||||
nTemp = 0;
|
||||
|
||||
nTemp |= (*pRawData << 0);
|
||||
CRC = (CRC >> 8) ^ CRC32_Table[(CRC & 0xFF) ^ *pRawData++];
|
||||
|
||||
nTemp |= (*pRawData << 8);
|
||||
CRC = (CRC >> 8) ^ CRC32_Table[(CRC & 0xFF) ^ *pRawData++];
|
||||
|
||||
nTemp |= (*pRawData << 16);
|
||||
CRC = (CRC >> 8) ^ CRC32_Table[(CRC & 0xFF) ^ *pRawData++];
|
||||
|
||||
if (nTemp & 0x800000)
|
||||
L = (int) (nTemp & 0x7fffff) - 0x800000;
|
||||
else
|
||||
L = (int) (nTemp & 0x7fffff);
|
||||
|
||||
// check the peak
|
||||
if (labs(L) > *pPeakLevel)
|
||||
*pPeakLevel = labs(L);
|
||||
if (labs(R) > *pPeakLevel)
|
||||
*pPeakLevel = labs(R);
|
||||
|
||||
// convert to x,y
|
||||
pOutputY[nBlockIndex] = L - R;
|
||||
pOutputX[nBlockIndex] = R + (pOutputY[nBlockIndex] / 2);
|
||||
|
||||
}
|
||||
}
|
||||
else if (pWaveFormatEx->nChannels == 1)
|
||||
{
|
||||
for (int nBlockIndex = 0; nBlockIndex < nTotalBlocks; nBlockIndex++)
|
||||
{
|
||||
unsigned __int32 nTemp = 0;
|
||||
|
||||
nTemp |= (*pRawData << 0);
|
||||
CRC = (CRC >> 8) ^ CRC32_Table[(CRC & 0xFF) ^ *pRawData++];
|
||||
|
||||
nTemp |= (*pRawData << 8);
|
||||
CRC = (CRC >> 8) ^ CRC32_Table[(CRC & 0xFF) ^ *pRawData++];
|
||||
|
||||
nTemp |= (*pRawData << 16);
|
||||
CRC = (CRC >> 8) ^ CRC32_Table[(CRC & 0xFF) ^ *pRawData++];
|
||||
|
||||
if (nTemp & 0x800000)
|
||||
R = (int) (nTemp & 0x7fffff) - 0x800000;
|
||||
else
|
||||
R = (int) (nTemp & 0x7fffff);
|
||||
|
||||
// check the peak
|
||||
if (labs(R) > *pPeakLevel)
|
||||
*pPeakLevel = labs(R);
|
||||
|
||||
// convert to x,y
|
||||
pOutputX[nBlockIndex] = R;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pWaveFormatEx->nChannels == 2)
|
||||
{
|
||||
int LPeak = 0;
|
||||
int RPeak = 0;
|
||||
int nBlockIndex = 0;
|
||||
for (nBlockIndex = 0; nBlockIndex < nTotalBlocks; nBlockIndex++)
|
||||
{
|
||||
|
||||
R = (int) *((__int16 *) pRawData);
|
||||
CRC = (CRC >> 8) ^ CRC32_Table[(CRC & 0xFF) ^ *pRawData++];
|
||||
CRC = (CRC >> 8) ^ CRC32_Table[(CRC & 0xFF) ^ *pRawData++];
|
||||
|
||||
L = (int) *((__int16 *) pRawData);
|
||||
CRC = (CRC >> 8) ^ CRC32_Table[(CRC & 0xFF) ^ *pRawData++];
|
||||
CRC = (CRC >> 8) ^ CRC32_Table[(CRC & 0xFF) ^ *pRawData++];
|
||||
|
||||
// check the peak
|
||||
if (labs(L) > LPeak)
|
||||
LPeak = labs(L);
|
||||
if (labs(R) > RPeak)
|
||||
RPeak = labs(R);
|
||||
|
||||
// convert to x,y
|
||||
pOutputY[nBlockIndex] = L - R;
|
||||
pOutputX[nBlockIndex] = R + (pOutputY[nBlockIndex] / 2);
|
||||
}
|
||||
|
||||
if (LPeak == 0) { *pSpecialCodes |= SPECIAL_FRAME_LEFT_SILENCE; }
|
||||
if (RPeak == 0) { *pSpecialCodes |= SPECIAL_FRAME_RIGHT_SILENCE; }
|
||||
if (max(LPeak, RPeak) > *pPeakLevel)
|
||||
{
|
||||
*pPeakLevel = max(LPeak, RPeak);
|
||||
}
|
||||
|
||||
// check for pseudo-stereo files
|
||||
nBlockIndex = 0;
|
||||
while (pOutputY[nBlockIndex++] == 0)
|
||||
{
|
||||
if (nBlockIndex == (nBytes / 4))
|
||||
{
|
||||
*pSpecialCodes |= SPECIAL_FRAME_PSEUDO_STEREO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else if (pWaveFormatEx->nChannels == 1)
|
||||
{
|
||||
int nPeak = 0;
|
||||
for (int nBlockIndex = 0; nBlockIndex < nTotalBlocks; nBlockIndex++)
|
||||
{
|
||||
R = (int) *((__int16 *) pRawData);
|
||||
|
||||
CRC = (CRC >> 8) ^ CRC32_Table[(CRC & 0xFF) ^ *pRawData++];
|
||||
CRC = (CRC >> 8) ^ CRC32_Table[(CRC & 0xFF) ^ *pRawData++];
|
||||
|
||||
// check the peak
|
||||
if (labs(R) > nPeak)
|
||||
nPeak = labs(R);
|
||||
|
||||
//convert to x,y
|
||||
pOutputX[nBlockIndex] = R;
|
||||
}
|
||||
|
||||
if (nPeak > *pPeakLevel)
|
||||
*pPeakLevel = nPeak;
|
||||
if (nPeak == 0) { *pSpecialCodes |= SPECIAL_FRAME_MONO_SILENCE; }
|
||||
}
|
||||
}
|
||||
|
||||
CRC = CRC ^ 0xFFFFFFFF;
|
||||
|
||||
// add the special code
|
||||
CRC >>= 1;
|
||||
|
||||
if (*pSpecialCodes != 0)
|
||||
{
|
||||
CRC |= (1 << 31);
|
||||
}
|
||||
|
||||
*pCRC = CRC;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CPrepare::Unprepare(int X, int Y, const WAVEFORMATEX * pWaveFormatEx, unsigned char * pOutput, unsigned int * pCRC)
|
||||
{
|
||||
#define CALCULATE_CRC_BYTE *pCRC = (*pCRC >> 8) ^ CRC32_Table[(*pCRC & 0xFF) ^ *pOutput++];
|
||||
// decompress and convert from (x,y) -> (l,r)
|
||||
// sort of long and ugly.... sorry
|
||||
|
||||
if (pWaveFormatEx->nChannels == 2)
|
||||
{
|
||||
if (pWaveFormatEx->wBitsPerSample == 16)
|
||||
{
|
||||
// get the right and left values
|
||||
int nR = X - (Y / 2);
|
||||
int nL = nR + Y;
|
||||
|
||||
// error check (for overflows)
|
||||
if ((nR < -32768) || (nR > 32767) || (nL < -32768) || (nL > 32767))
|
||||
{
|
||||
throw(-1);
|
||||
}
|
||||
|
||||
*(__int16 *) pOutput = (__int16) nR;
|
||||
CALCULATE_CRC_BYTE
|
||||
CALCULATE_CRC_BYTE
|
||||
|
||||
*(__int16 *) pOutput = (__int16) nL;
|
||||
CALCULATE_CRC_BYTE
|
||||
CALCULATE_CRC_BYTE
|
||||
}
|
||||
else if (pWaveFormatEx->wBitsPerSample == 8)
|
||||
{
|
||||
unsigned char R = (X - (Y / 2) + 128);
|
||||
*pOutput = R;
|
||||
CALCULATE_CRC_BYTE
|
||||
*pOutput = (unsigned char) (R + Y);
|
||||
CALCULATE_CRC_BYTE
|
||||
}
|
||||
else if (pWaveFormatEx->wBitsPerSample == 24)
|
||||
{
|
||||
__int32 RV, LV;
|
||||
|
||||
RV = X - (Y / 2);
|
||||
LV = RV + Y;
|
||||
|
||||
unsigned __int32 nTemp = 0;
|
||||
if (RV < 0)
|
||||
nTemp = ((unsigned __int32) (RV + 0x800000)) | 0x800000;
|
||||
else
|
||||
nTemp = (unsigned __int32) RV;
|
||||
|
||||
*pOutput = (unsigned char) ((nTemp >> 0) & 0xFF);
|
||||
CALCULATE_CRC_BYTE
|
||||
*pOutput = (unsigned char) ((nTemp >> 8) & 0xFF);
|
||||
CALCULATE_CRC_BYTE
|
||||
*pOutput = (unsigned char) ((nTemp >> 16) & 0xFF);
|
||||
CALCULATE_CRC_BYTE
|
||||
|
||||
nTemp = 0;
|
||||
if (LV < 0)
|
||||
nTemp = ((unsigned __int32) (LV + 0x800000)) | 0x800000;
|
||||
else
|
||||
nTemp = (unsigned __int32) LV;
|
||||
|
||||
*pOutput = (unsigned char) ((nTemp >> 0) & 0xFF);
|
||||
CALCULATE_CRC_BYTE
|
||||
|
||||
*pOutput = (unsigned char) ((nTemp >> 8) & 0xFF);
|
||||
CALCULATE_CRC_BYTE
|
||||
|
||||
*pOutput = (unsigned char) ((nTemp >> 16) & 0xFF);
|
||||
CALCULATE_CRC_BYTE
|
||||
}
|
||||
}
|
||||
else if (pWaveFormatEx->nChannels == 1)
|
||||
{
|
||||
if (pWaveFormatEx->wBitsPerSample == 16)
|
||||
{
|
||||
__int16 R = X;
|
||||
|
||||
*(__int16 *) pOutput = (__int16) R;
|
||||
CALCULATE_CRC_BYTE
|
||||
CALCULATE_CRC_BYTE
|
||||
}
|
||||
else if (pWaveFormatEx->wBitsPerSample == 8)
|
||||
{
|
||||
unsigned char R = X + 128;
|
||||
*pOutput = R;
|
||||
CALCULATE_CRC_BYTE
|
||||
}
|
||||
else if (pWaveFormatEx->wBitsPerSample == 24)
|
||||
{
|
||||
__int32 RV = X;
|
||||
|
||||
unsigned __int32 nTemp = 0;
|
||||
if (RV < 0)
|
||||
nTemp = ((unsigned __int32) (RV + 0x800000)) | 0x800000;
|
||||
else
|
||||
nTemp = (unsigned __int32) RV;
|
||||
|
||||
*pOutput = (unsigned char) ((nTemp >> 0) & 0xFF);
|
||||
CALCULATE_CRC_BYTE
|
||||
*pOutput = (unsigned char) ((nTemp >> 8) & 0xFF);
|
||||
CALCULATE_CRC_BYTE
|
||||
*pOutput = (unsigned char) ((nTemp >> 16) & 0xFF);
|
||||
CALCULATE_CRC_BYTE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef BACKWARDS_COMPATIBILITY
|
||||
|
||||
int CPrepare::UnprepareOld(int *pInputX, int *pInputY, int nBlocks, const WAVEFORMATEX *pWaveFormatEx, unsigned char *pRawData, unsigned int *pCRC, int *pSpecialCodes, int nFileVersion)
|
||||
{
|
||||
//the CRC that will be figured during decompression
|
||||
unsigned __int32 CRC = 0xffffffff;
|
||||
|
||||
//decompress and convert from (x,y) -> (l,r)
|
||||
//sort of int and ugly.... sorry
|
||||
if (pWaveFormatEx->nChannels == 2)
|
||||
{
|
||||
//convert the x,y data to raw data
|
||||
if (pWaveFormatEx->wBitsPerSample == 16)
|
||||
{
|
||||
__int16 R;
|
||||
unsigned char *Buffer = &pRawData[0];
|
||||
int *pX = pInputX;
|
||||
int *pY = pInputY;
|
||||
|
||||
for (; pX < &pInputX[nBlocks]; pX++, pY++)
|
||||
{
|
||||
R = *pX - (*pY / 2);
|
||||
|
||||
*(__int16 *) Buffer = (__int16) R;
|
||||
CRC = (CRC >> 8) ^ CRC32_Table[(CRC & 0xFF) ^ *Buffer++];
|
||||
CRC = (CRC >> 8) ^ CRC32_Table[(CRC & 0xFF) ^ *Buffer++];
|
||||
|
||||
*(__int16 *) Buffer = (__int16) R + *pY;
|
||||
CRC = (CRC >> 8) ^ CRC32_Table[(CRC & 0xFF) ^ *Buffer++];
|
||||
CRC = (CRC >> 8) ^ CRC32_Table[(CRC & 0xFF) ^ *Buffer++];
|
||||
}
|
||||
}
|
||||
else if (pWaveFormatEx->wBitsPerSample == 8)
|
||||
{
|
||||
unsigned char *R = (unsigned char *) &pRawData[0];
|
||||
unsigned char *L = (unsigned char *) &pRawData[1];
|
||||
|
||||
if (nFileVersion > 3830)
|
||||
{
|
||||
for (int SampleIndex = 0; SampleIndex < nBlocks; SampleIndex++, L+=2, R+=2)
|
||||
{
|
||||
*R = (unsigned char) (pInputX[SampleIndex] - (pInputY[SampleIndex] / 2) + 128);
|
||||
CRC = (CRC >> 8) ^ CRC32_Table[(CRC & 0xFF) ^ *R];
|
||||
*L = (unsigned char) (*R + pInputY[SampleIndex]);
|
||||
CRC = (CRC >> 8) ^ CRC32_Table[(CRC & 0xFF) ^ *L];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int SampleIndex = 0; SampleIndex < nBlocks; SampleIndex++, L+=2, R+=2)
|
||||
{
|
||||
*R = (unsigned char) (pInputX[SampleIndex] - (pInputY[SampleIndex] / 2));
|
||||
CRC = (CRC >> 8) ^ CRC32_Table[(CRC & 0xFF) ^ *R];
|
||||
*L = (unsigned char) (*R + pInputY[SampleIndex]);
|
||||
CRC = (CRC >> 8) ^ CRC32_Table[(CRC & 0xFF) ^ *L];
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (pWaveFormatEx->wBitsPerSample == 24)
|
||||
{
|
||||
unsigned char *Buffer = (unsigned char *) &pRawData[0];
|
||||
__int32 RV, LV;
|
||||
|
||||
for (int SampleIndex = 0; SampleIndex < nBlocks; SampleIndex++)
|
||||
{
|
||||
RV = pInputX[SampleIndex] - (pInputY[SampleIndex] / 2);
|
||||
LV = RV + pInputY[SampleIndex];
|
||||
|
||||
unsigned __int32 nTemp = 0;
|
||||
if (RV < 0)
|
||||
nTemp = ((unsigned __int32) (RV + 0x800000)) | 0x800000;
|
||||
else
|
||||
nTemp = (unsigned __int32) RV;
|
||||
|
||||
*Buffer = (unsigned char) ((nTemp >> 0) & 0xFF);
|
||||
CRC = (CRC >> 8) ^ CRC32_Table[(CRC & 0xFF) ^ *Buffer++];
|
||||
|
||||
*Buffer = (unsigned char) ((nTemp >> 8) & 0xFF);
|
||||
CRC = (CRC >> 8) ^ CRC32_Table[(CRC & 0xFF) ^ *Buffer++];
|
||||
|
||||
*Buffer = (unsigned char) ((nTemp >> 16) & 0xFF);
|
||||
CRC = (CRC >> 8) ^ CRC32_Table[(CRC & 0xFF) ^ *Buffer++];
|
||||
|
||||
nTemp = 0;
|
||||
if (LV < 0)
|
||||
nTemp = ((unsigned __int32) (LV + 0x800000)) | 0x800000;
|
||||
else
|
||||
nTemp = (unsigned __int32) LV;
|
||||
|
||||
*Buffer = (unsigned char) ((nTemp >> 0) & 0xFF);
|
||||
CRC = (CRC >> 8) ^ CRC32_Table[(CRC & 0xFF) ^ *Buffer++];
|
||||
|
||||
*Buffer = (unsigned char) ((nTemp >> 8) & 0xFF);
|
||||
CRC = (CRC >> 8) ^ CRC32_Table[(CRC & 0xFF) ^ *Buffer++];
|
||||
|
||||
*Buffer = (unsigned char) ((nTemp >> 16) & 0xFF);
|
||||
CRC = (CRC >> 8) ^ CRC32_Table[(CRC & 0xFF) ^ *Buffer++];
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (pWaveFormatEx->nChannels == 1)
|
||||
{
|
||||
//convert to raw data
|
||||
if (pWaveFormatEx->wBitsPerSample == 8)
|
||||
{
|
||||
unsigned char *R = (unsigned char *) &pRawData[0];
|
||||
|
||||
if (nFileVersion > 3830)
|
||||
{
|
||||
for (int SampleIndex = 0; SampleIndex < nBlocks; SampleIndex++, R++)
|
||||
{
|
||||
*R = pInputX[SampleIndex] + 128;
|
||||
CRC = (CRC >> 8) ^ CRC32_Table[(CRC & 0xFF) ^ *R];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int SampleIndex = 0; SampleIndex < nBlocks; SampleIndex++, R++)
|
||||
{
|
||||
*R = (unsigned char) (pInputX[SampleIndex]);
|
||||
CRC = (CRC >> 8) ^ CRC32_Table[(CRC & 0xFF) ^ *R];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else if (pWaveFormatEx->wBitsPerSample == 24)
|
||||
{
|
||||
|
||||
unsigned char *Buffer = (unsigned char *) &pRawData[0];
|
||||
__int32 RV;
|
||||
for (int SampleIndex = 0; SampleIndex<nBlocks; SampleIndex++)
|
||||
{
|
||||
RV = pInputX[SampleIndex];
|
||||
|
||||
unsigned __int32 nTemp = 0;
|
||||
if (RV < 0)
|
||||
nTemp = ((unsigned __int32) (RV + 0x800000)) | 0x800000;
|
||||
else
|
||||
nTemp = (unsigned __int32) RV;
|
||||
|
||||
*Buffer = (unsigned char) ((nTemp >> 0) & 0xFF);
|
||||
CRC = (CRC >> 8) ^ CRC32_Table[(CRC & 0xFF) ^ *Buffer++];
|
||||
|
||||
*Buffer = (unsigned char) ((nTemp >> 8) & 0xFF);
|
||||
CRC = (CRC >> 8) ^ CRC32_Table[(CRC & 0xFF) ^ *Buffer++];
|
||||
|
||||
*Buffer = (unsigned char) ((nTemp >> 16) & 0xFF);
|
||||
CRC = (CRC >> 8) ^ CRC32_Table[(CRC & 0xFF) ^ *Buffer++];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned char *Buffer = &pRawData[0];
|
||||
|
||||
for (int SampleIndex = 0; SampleIndex < nBlocks; SampleIndex++)
|
||||
{
|
||||
*(__int16 *) Buffer = (__int16) (pInputX[SampleIndex]);
|
||||
CRC = (CRC >> 8) ^ CRC32_Table[(CRC & 0xFF) ^ *Buffer++];
|
||||
CRC = (CRC >> 8) ^ CRC32_Table[(CRC & 0xFF) ^ *Buffer++];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CRC = CRC ^ 0xffffffff;
|
||||
|
||||
*pCRC = CRC;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // BACKWARDS_COMPATIBILITY
|
37
gst/monkeyaudio/libmonkeyaudio/Prepare.h
Normal file
37
gst/monkeyaudio/libmonkeyaudio/Prepare.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
#ifndef APE_PREPARE_H
|
||||
#define APE_PREPARE_H
|
||||
|
||||
#define SPECIAL_FRAME_MONO_SILENCE 1
|
||||
#define SPECIAL_FRAME_LEFT_SILENCE 1
|
||||
#define SPECIAL_FRAME_RIGHT_SILENCE 2
|
||||
#define SPECIAL_FRAME_PSEUDO_STEREO 4
|
||||
|
||||
/*****************************************************************************
|
||||
Manage the preparation stage of compression and decompression
|
||||
|
||||
Tasks:
|
||||
|
||||
1) convert data to 32-bit
|
||||
2) convert L,R to X,Y
|
||||
3) calculate the CRC
|
||||
4) do simple analysis
|
||||
5) check for the peak value
|
||||
*****************************************************************************/
|
||||
|
||||
class IPredictorDecompress;
|
||||
|
||||
class CPrepare
|
||||
{
|
||||
public:
|
||||
|
||||
int Prepare(unsigned char *pRawData, int nBytes, const WAVEFORMATEX *pWaveFormatEx, int *pOutputX, int *pOutputY, unsigned int *pCRC, int *pSpecialCodes, int *pPeakLevel);
|
||||
void Unprepare(int X, int Y, const WAVEFORMATEX * pWaveFormatEx, unsigned char * pOutput, unsigned int * pCRC);
|
||||
|
||||
|
||||
#ifdef BACKWARDS_COMPATIBILITY
|
||||
int UnprepareOld(int *pInputX, int *pInputY, int nBlocks, const WAVEFORMATEX *pWaveFormatEx, unsigned char *pRawData, unsigned int *pCRC, int *pSpecialCodes, int nFileVersion);
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
#endif /* APE_PREPARE_H */
|
120
gst/monkeyaudio/libmonkeyaudio/RollBuffer.h
Normal file
120
gst/monkeyaudio/libmonkeyaudio/RollBuffer.h
Normal file
|
@ -0,0 +1,120 @@
|
|||
#ifndef APE_ROLLBUFFER_H
|
||||
#define APE_ROLLBUFFER_H
|
||||
|
||||
template <class TYPE> class CRollBuffer
|
||||
{
|
||||
public:
|
||||
|
||||
CRollBuffer()
|
||||
{
|
||||
m_pData = NULL;
|
||||
m_pCurrent = NULL;
|
||||
}
|
||||
|
||||
~CRollBuffer()
|
||||
{
|
||||
SAFE_ARRAY_DELETE(m_pData);
|
||||
}
|
||||
|
||||
int Create(int nWindowElements, int nHistoryElements)
|
||||
{
|
||||
SAFE_ARRAY_DELETE(m_pData)
|
||||
m_nWindowElements = nWindowElements;
|
||||
m_nHistoryElements = nHistoryElements;
|
||||
|
||||
m_pData = new TYPE[m_nWindowElements + m_nHistoryElements];
|
||||
if (m_pData == NULL)
|
||||
return ERROR_INSUFFICIENT_MEMORY;
|
||||
|
||||
Flush();
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Flush()
|
||||
{
|
||||
ZeroMemory(m_pData, (m_nHistoryElements + 1) * sizeof(TYPE));
|
||||
m_pCurrent = &m_pData[m_nHistoryElements];
|
||||
}
|
||||
|
||||
void Roll()
|
||||
{
|
||||
memcpy(&m_pData[0], &m_pCurrent[-m_nHistoryElements], m_nHistoryElements * sizeof(TYPE));
|
||||
m_pCurrent = &m_pData[m_nHistoryElements];
|
||||
}
|
||||
|
||||
__inline void IncrementSafe()
|
||||
{
|
||||
m_pCurrent++;
|
||||
if (m_pCurrent == &m_pData[m_nWindowElements + m_nHistoryElements])
|
||||
Roll();
|
||||
}
|
||||
|
||||
__inline void IncrementFast()
|
||||
{
|
||||
m_pCurrent++;
|
||||
}
|
||||
|
||||
__inline TYPE & operator[](const int nIndex) const
|
||||
{
|
||||
return m_pCurrent[nIndex];
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
TYPE * m_pData;
|
||||
TYPE * m_pCurrent;
|
||||
int m_nHistoryElements;
|
||||
int m_nWindowElements;
|
||||
};
|
||||
|
||||
template <class TYPE, int WINDOW_ELEMENTS, int HISTORY_ELEMENTS> class CRollBufferFast
|
||||
{
|
||||
public:
|
||||
|
||||
CRollBufferFast()
|
||||
{
|
||||
m_pData = new TYPE[WINDOW_ELEMENTS + HISTORY_ELEMENTS];
|
||||
Flush();
|
||||
}
|
||||
|
||||
~CRollBufferFast()
|
||||
{
|
||||
SAFE_ARRAY_DELETE(m_pData);
|
||||
}
|
||||
|
||||
void Flush()
|
||||
{
|
||||
ZeroMemory(m_pData, (HISTORY_ELEMENTS + 1) * sizeof(TYPE));
|
||||
m_pCurrent = &m_pData[HISTORY_ELEMENTS];
|
||||
}
|
||||
|
||||
void Roll()
|
||||
{
|
||||
memcpy(&m_pData[0], &m_pCurrent[-HISTORY_ELEMENTS], HISTORY_ELEMENTS * sizeof(TYPE));
|
||||
m_pCurrent = &m_pData[HISTORY_ELEMENTS];
|
||||
}
|
||||
|
||||
__inline void IncrementSafe()
|
||||
{
|
||||
m_pCurrent++;
|
||||
if (m_pCurrent == &m_pData[WINDOW_ELEMENTS + HISTORY_ELEMENTS])
|
||||
Roll();
|
||||
}
|
||||
|
||||
__inline void IncrementFast()
|
||||
{
|
||||
m_pCurrent++;
|
||||
}
|
||||
|
||||
__inline TYPE & operator[](const int nIndex) const
|
||||
{
|
||||
return m_pCurrent[nIndex];
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
TYPE * m_pData;
|
||||
TYPE * m_pCurrent;
|
||||
};
|
||||
|
||||
#endif /* APE_ROLLBUFFER_H */
|
31
gst/monkeyaudio/libmonkeyaudio/ScaledFirstOrderFilter.h
Normal file
31
gst/monkeyaudio/libmonkeyaudio/ScaledFirstOrderFilter.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
#ifndef APE_SCALEFIRSTORDERFILER_H
|
||||
#define APE_SCALEFIRSTORDERFILER_H
|
||||
|
||||
template <int MULTIPLY, int SHIFT> class CScaledFirstOrderFilter
|
||||
{
|
||||
public:
|
||||
|
||||
__inline void Flush()
|
||||
{
|
||||
m_nLastValue = 0;
|
||||
}
|
||||
|
||||
__inline int Compress(const int nInput)
|
||||
{
|
||||
int nRetVal = nInput - ((m_nLastValue * MULTIPLY) >> SHIFT);
|
||||
m_nLastValue = nInput;
|
||||
return nRetVal;
|
||||
}
|
||||
|
||||
__inline int Decompress(const int nInput)
|
||||
{
|
||||
m_nLastValue = nInput + ((m_nLastValue * MULTIPLY) >> SHIFT);
|
||||
return m_nLastValue;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
int m_nLastValue;
|
||||
};
|
||||
|
||||
#endif /* APE_SCALEFIRSTORDERFILER_H */
|
89
gst/monkeyaudio/libmonkeyaudio/SmartPtr.h
Normal file
89
gst/monkeyaudio/libmonkeyaudio/SmartPtr.h
Normal file
|
@ -0,0 +1,89 @@
|
|||
#ifndef APE_SMARTPTR_H
|
||||
#define APE_SMARTPTR_H
|
||||
|
||||
// disable the operator -> on UDT warning
|
||||
#ifdef _WIN32
|
||||
# pragma warning( push )
|
||||
# pragma warning( disable : 4284 )
|
||||
#endif
|
||||
|
||||
/*************************************************************************************************
|
||||
CSmartPtr - a simple smart pointer class that can automatically initialize and free memory
|
||||
note: (doesn't do garbage collection / reference counting because of the many pitfalls)
|
||||
*************************************************************************************************/
|
||||
template <class TYPE> class CSmartPtr
|
||||
{
|
||||
public:
|
||||
TYPE * m_pObject;
|
||||
BOOL m_bArray;
|
||||
BOOL m_bDelete;
|
||||
|
||||
CSmartPtr()
|
||||
{
|
||||
m_bDelete = TRUE;
|
||||
m_pObject = NULL;
|
||||
}
|
||||
CSmartPtr(TYPE * a_pObject, BOOL a_bArray = FALSE, BOOL a_bDelete = TRUE)
|
||||
{
|
||||
m_bDelete = TRUE;
|
||||
m_pObject = NULL;
|
||||
Assign(a_pObject, a_bArray, a_bDelete);
|
||||
}
|
||||
|
||||
~CSmartPtr()
|
||||
{
|
||||
Delete();
|
||||
}
|
||||
|
||||
void Assign(TYPE * a_pObject, BOOL a_bArray = FALSE, BOOL a_bDelete = TRUE)
|
||||
{
|
||||
Delete();
|
||||
|
||||
m_bDelete = a_bDelete;
|
||||
m_bArray = a_bArray;
|
||||
m_pObject = a_pObject;
|
||||
}
|
||||
|
||||
void Delete()
|
||||
{
|
||||
if (m_bDelete && m_pObject)
|
||||
{
|
||||
if (m_bArray)
|
||||
delete [] m_pObject;
|
||||
else
|
||||
delete m_pObject;
|
||||
|
||||
m_pObject = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void SetDelete(const BOOL a_bDelete)
|
||||
{
|
||||
m_bDelete = a_bDelete;
|
||||
}
|
||||
|
||||
__inline TYPE * GetPtr() const
|
||||
{
|
||||
return m_pObject;
|
||||
}
|
||||
|
||||
__inline operator TYPE * () const
|
||||
{
|
||||
return m_pObject;
|
||||
}
|
||||
|
||||
__inline TYPE * operator ->() const
|
||||
{
|
||||
return m_pObject;
|
||||
}
|
||||
|
||||
// declare assignment, but don't implement (compiler error if we try to use)
|
||||
// that way we can't carelessly mix smart pointers and regular pointers
|
||||
__inline void * operator =(void *) const;
|
||||
};
|
||||
|
||||
#ifdef _WIN32
|
||||
# pragma warning( pop )
|
||||
#endif
|
||||
|
||||
#endif /* APE_SMARTPTR_H */
|
238
gst/monkeyaudio/libmonkeyaudio/StdLibFileIO.cpp
Normal file
238
gst/monkeyaudio/libmonkeyaudio/StdLibFileIO.cpp
Normal file
|
@ -0,0 +1,238 @@
|
|||
#include "All.h"
|
||||
|
||||
#ifdef IO_USE_STD_LIB_FILE_IO
|
||||
|
||||
#include "StdLibFileIO.h"
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
|
||||
// low level I/O, where are prototypes and constants?
|
||||
#if defined _WIN32 || defined __TURBOC__ || defined __ZTC__ || defined _MSC_VER
|
||||
# include <io.h>
|
||||
# include <fcntl.h>
|
||||
# include <time.h>
|
||||
# include <sys/types.h>
|
||||
# include <sys/stat.h>
|
||||
#elif defined __unix__ || defined __linux__
|
||||
# include <fcntl.h>
|
||||
# include <unistd.h>
|
||||
# include <sys/time.h>
|
||||
# include <sys/ioctl.h>
|
||||
# include <sys/types.h>
|
||||
# include <sys/stat.h>
|
||||
#else
|
||||
// .... hier Includes für neues Betriebssystem einfügen (mit vorgestellten: #elif defined)
|
||||
# include <fcntl.h>
|
||||
# include <unistd.h>
|
||||
# include <sys/ioctl.h>
|
||||
# include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef O_BINARY
|
||||
# ifdef _O_BINARY
|
||||
# define O_BINARY _O_BINARY
|
||||
# else
|
||||
# define O_BINARY 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
//// Binary/Low-Level-IO ///////////////////////////////////////////
|
||||
//
|
||||
// All file I/O is basicly handled via an ANSI file pointer (type: FILE*) in
|
||||
// FILEIO-Mode 1 and via a POSIX file descriptor (type: int) in
|
||||
// FILEIO-Mode 2 and 3.
|
||||
//
|
||||
// Some operation are only available via the POSIX interface (fcntl, setmode,
|
||||
// ...) so we need a function to get the file descriptor from a file pointer.
|
||||
// In FILEIO-Mode 2 and 3 this is a dummy function because we always working
|
||||
// with this file descriptors.
|
||||
//
|
||||
|
||||
#if defined __BORLANDC__ || defined _WIN32
|
||||
# define FILENO(__fp) _fileno ((__fp))
|
||||
#elif defined __CYGWIN__ || defined __TURBOC__ || defined __unix__ || defined __EMX__ || defined _MSC_VER
|
||||
# define FILENO(__fp) fileno ((__fp))
|
||||
#else
|
||||
# define FILENO(__fp) fileno ((__fp))
|
||||
#endif
|
||||
|
||||
|
||||
//
|
||||
// If we have access to a file via file name, we can open the file with an
|
||||
// additional "b" or a O_BINARY within the (f)open function to get a
|
||||
// transparent untranslated data stream which is necessary for audio bitstream
|
||||
// data and also for PCM data. If we are working with
|
||||
// stdin/stdout/FILENO_STDIN/FILENO_STDOUT we can't open the file with this
|
||||
// attributes, because the files are already open. So we need a non
|
||||
// standardized sequence to switch to this mode (not necessary for Unix).
|
||||
// Mostly the sequency is the same for incoming and outgoing streams, but only
|
||||
// mostly so we need one for IN and one for OUT.
|
||||
// Macros are called with the file pointer and you get back the untransalted file
|
||||
// pointer which can be equal or different from the original.
|
||||
//
|
||||
|
||||
#if defined __EMX__
|
||||
# define SETBINARY_IN(__fp) (_fsetmode ( (__fp), "b" ), (__fp))
|
||||
# define SETBINARY_OUT(__fp) (_fsetmode ( (__fp), "b" ), (__fp))
|
||||
#elif defined __TURBOC__ || defined __BORLANDC__
|
||||
# define SETBINARY_IN(__fp) (setmode ( FILENO ((__fp)), O_BINARY ), (__fp))
|
||||
# define SETBINARY_OUT(__fp) (setmode ( FILENO ((__fp)), O_BINARY ), (__fp))
|
||||
#elif defined __CYGWIN__
|
||||
# define SETBINARY_IN(__fp) (setmode ( FILENO ((__fp)), _O_BINARY ), (__fp))
|
||||
# define SETBINARY_OUT(__fp) (setmode ( FILENO ((__fp)), _O_BINARY ), (__fp))
|
||||
#elif defined _WIN32
|
||||
# define SETBINARY_IN(__fp) (_setmode ( FILENO ((__fp)), _O_BINARY ), (__fp))
|
||||
# define SETBINARY_OUT(__fp) (_setmode ( FILENO ((__fp)), _O_BINARY ), (__fp))
|
||||
#elif defined _MSC_VER
|
||||
# define SETBINARY_IN(__fp) (setmode ( FILENO ((__fp)), O_BINARY ), (__fp))
|
||||
# define SETBINARY_OUT(__fp) (setmode ( FILENO ((__fp)), O_BINARY ), (__fp))
|
||||
#elif defined __unix__
|
||||
# define SETBINARY_IN(__fp) (__fp)
|
||||
# define SETBINARY_OUT(__fp) (__fp)
|
||||
#elif 0
|
||||
# define SETBINARY_IN(__fp) (freopen ( NULL, "rb", (__fp) ), (__fp))
|
||||
# define SETBINARY_OUT(__fp) (freopen ( NULL, "wb", (__fp) ), (__fp))
|
||||
#else
|
||||
# define SETBINARY_IN(__fp) (__fp)
|
||||
# define SETBINARY_OUT(__fp) (__fp)
|
||||
#endif
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
|
||||
CStdLibFileIO::CStdLibFileIO()
|
||||
{
|
||||
memset(m_cFileName, 0, MAX_PATH);
|
||||
m_bReadOnly = FALSE;
|
||||
m_pFile = NULL;
|
||||
}
|
||||
|
||||
CStdLibFileIO::~CStdLibFileIO()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
int CStdLibFileIO::GetHandle()
|
||||
{
|
||||
return FILENO (m_pFile);
|
||||
}
|
||||
|
||||
int CStdLibFileIO::Open(const char * pName)
|
||||
{
|
||||
Close();
|
||||
|
||||
m_bReadOnly = FALSE;
|
||||
|
||||
if ( 0 == strcmp (pName, "-") || 0 == strcmp (pName, "/dev/stdin") ) {
|
||||
m_pFile = SETBINARY_IN (stdin);
|
||||
m_bReadOnly = TRUE; // ReadOnly
|
||||
}
|
||||
else if ( 0 == strcmp (pName, "/dev/stdout") ) {
|
||||
m_pFile = SETBINARY_OUT (stdout);
|
||||
m_bReadOnly = FALSE; // WriteOnly
|
||||
}
|
||||
else {
|
||||
m_pFile = fopen (pName, "r+b");
|
||||
m_bReadOnly = FALSE; // Read/Write
|
||||
}
|
||||
|
||||
if (!m_pFile)
|
||||
return -1;
|
||||
|
||||
strcpy(m_cFileName, pName);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CStdLibFileIO::Close()
|
||||
{
|
||||
int ret = -1;
|
||||
|
||||
if ( m_pFile != NULL ) {
|
||||
ret = fclose(m_pFile);
|
||||
m_pFile = NULL;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int CStdLibFileIO::Read(void * pBuffer, unsigned int nBytesToRead, unsigned int * pBytesRead)
|
||||
{
|
||||
*pBytesRead = fread(pBuffer, 1, nBytesToRead, m_pFile);
|
||||
return ferror(m_pFile) ? ERROR_IO_READ : 0;
|
||||
}
|
||||
|
||||
int CStdLibFileIO::Write(const void * pBuffer, unsigned int nBytesToWrite, unsigned int * pBytesWritten)
|
||||
{
|
||||
*pBytesWritten = fwrite(pBuffer, 1, nBytesToWrite, m_pFile);
|
||||
|
||||
return (ferror(m_pFile) || (*pBytesWritten != nBytesToWrite)) ? ERROR_IO_WRITE : 0;
|
||||
}
|
||||
|
||||
int CStdLibFileIO::Seek(int nDistance, unsigned int nMoveMode)
|
||||
{
|
||||
return fseek(m_pFile, nDistance, nMoveMode);
|
||||
}
|
||||
|
||||
int CStdLibFileIO::SetEOF()
|
||||
{
|
||||
return ftruncate (GetHandle(), GetPosition() );
|
||||
}
|
||||
|
||||
int CStdLibFileIO::GetPosition()
|
||||
{
|
||||
fpos_t fPosition;
|
||||
|
||||
memset(&fPosition, 0, sizeof(fPosition));
|
||||
fgetpos(m_pFile, &fPosition);
|
||||
return _FPOSOFF(fPosition);
|
||||
}
|
||||
|
||||
int CStdLibFileIO::GetSize()
|
||||
{
|
||||
int nCurrentPosition = GetPosition();
|
||||
Seek(0, FILE_END);
|
||||
int nLength = GetPosition();
|
||||
Seek(nCurrentPosition, FILE_BEGIN);
|
||||
return nLength;
|
||||
}
|
||||
|
||||
int CStdLibFileIO::GetName(char * pBuffer)
|
||||
{
|
||||
strcpy(pBuffer, m_cFileName);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CStdLibFileIO::Create(const char * pName)
|
||||
{
|
||||
Close();
|
||||
|
||||
if ( 0 == strcmp (pName, "-") || 0 == strcmp (pName, "/dev/stdout") ) {
|
||||
m_pFile = SETBINARY_OUT (stdout);
|
||||
m_bReadOnly = FALSE; // WriteOnly
|
||||
}
|
||||
else {
|
||||
m_pFile = fopen (pName, "w+b"); // Read/Write
|
||||
m_bReadOnly = FALSE;
|
||||
}
|
||||
|
||||
if (!m_pFile)
|
||||
return -1;
|
||||
|
||||
strcpy (m_cFileName, pName);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CStdLibFileIO::Delete()
|
||||
{
|
||||
#if 0
|
||||
Close();
|
||||
return unlink (m_cFileName); // 0 success, -1 error
|
||||
#endif
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif // #ifdef IO_USE_STD_LIB_FILE_IO
|
48
gst/monkeyaudio/libmonkeyaudio/StdLibFileIO.h
Normal file
48
gst/monkeyaudio/libmonkeyaudio/StdLibFileIO.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
#ifdef IO_USE_STD_LIB_FILE_IO
|
||||
|
||||
#ifndef APE_STDLIBFILEIO_H
|
||||
#define APE_STDLIBFILEIO_H
|
||||
|
||||
#include "IO.h"
|
||||
|
||||
class CStdLibFileIO : public CIO
|
||||
{
|
||||
public:
|
||||
//construction / destruction
|
||||
CStdLibFileIO();
|
||||
~CStdLibFileIO();
|
||||
|
||||
// open / close
|
||||
int Open(const char * pName);
|
||||
int Close();
|
||||
|
||||
// read / write
|
||||
int Read(void * pBuffer, unsigned int nBytesToRead, unsigned int * pBytesRead);
|
||||
int Write(const void * pBuffer, unsigned int nBytesToWrite, unsigned int * pBytesWritten);
|
||||
|
||||
// seek
|
||||
int Seek(int nDistance, unsigned int nMoveMode);
|
||||
|
||||
// other functions
|
||||
int SetEOF();
|
||||
|
||||
// creation / destruction
|
||||
int Create(const char * pName);
|
||||
int Delete();
|
||||
|
||||
// attributes
|
||||
int GetPosition();
|
||||
int GetSize();
|
||||
int GetName(char * pBuffer);
|
||||
int GetHandle();
|
||||
|
||||
private:
|
||||
|
||||
char m_cFileName[MAX_PATH];
|
||||
BOOL m_bReadOnly;
|
||||
FILE * m_pFile;
|
||||
};
|
||||
|
||||
#endif /* APE_STDLIBFILEIO_H */
|
||||
|
||||
#endif // IO_USE_STD_LIB_FILE_IO
|
203
gst/monkeyaudio/libmonkeyaudio/UnBitArray.cpp
Normal file
203
gst/monkeyaudio/libmonkeyaudio/UnBitArray.cpp
Normal file
|
@ -0,0 +1,203 @@
|
|||
#include "All.h"
|
||||
#include "APEInfo.h"
|
||||
#include "UnBitArray.h"
|
||||
#include "BitArray.h"
|
||||
|
||||
const unsigned __int32 POWERS_OF_TWO_MINUS_ONE_REVERSED[33] = {4294967295LU,2147483647,1073741823,536870911,268435455,134217727,67108863,33554431,16777215,8388607,4194303,2097151,1048575,524287,262143,131071,65535,32767,16383,8191,4095,2047,1023,511,255,127,63,31,15,7,3,1,0};
|
||||
|
||||
const unsigned __int32 K_SUM_MIN_BOUNDARY[32] = {0,32,64,128,256,512,1024,2048,4096,8192,16384,32768,65536,131072,262144,524288,1048576,2097152,4194304,8388608,16777216,33554432,67108864,134217728,268435456,536870912,1073741824,2147483648LU,0,0,0,0};
|
||||
|
||||
const __int32 RANGE_TOTAL[65] = {0,14824,28224,39348,47855,53994,58171,60926,62682,63786,64463,64878,65126,65276,65365,65419,65450,65469,65480,65487,65491,65493,65494,65495,65496,65497,65498,65499,65500,65501,65502,65503,65504,65505,65506,65507,65508,65509,65510,65511,65512,65513,65514,65515,65516,65517,65518,65519,65520,65521,65522,65523,65524,65525,65526,65527,65528,65529,65530,65531,65532,65533,65534,65535,65536};
|
||||
const __int32 RANGE_WIDTH[64] = {14824,13400,11124,8507,6139,4177,2755,1756,1104,677,415,248,150,89,54,31,19,11,7,4,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
|
||||
|
||||
#define RANGE_OVERFLOW_TOTAL_WIDTH 65536
|
||||
#define RANGE_OVERFLOW_SHIFT 16
|
||||
|
||||
#define CODE_BITS 32
|
||||
#define TOP_VALUE ((unsigned int ) 1 << (CODE_BITS - 1))
|
||||
#define SHIFT_BITS (CODE_BITS - 9)
|
||||
#define EXTRA_BITS ((CODE_BITS - 2) % 8 + 1)
|
||||
#define BOTTOM_VALUE (TOP_VALUE >> 8)
|
||||
|
||||
#define MODEL_ELEMENTS 64
|
||||
|
||||
/***********************************************************************************
|
||||
Construction
|
||||
***********************************************************************************/
|
||||
CUnBitArray::CUnBitArray(IAPEDecompress *pAPEDecompress, int nVersion)
|
||||
: CUnBitArrayBase(pAPEDecompress, nVersion)
|
||||
{
|
||||
CreateHelper(pAPEDecompress, 16384, nVersion);
|
||||
m_nFlushCounter = 0;
|
||||
m_nFinalizeCounter = 0;
|
||||
}
|
||||
|
||||
CUnBitArray::~CUnBitArray()
|
||||
{
|
||||
SAFE_ARRAY_DELETE(m_pBitArray)
|
||||
}
|
||||
|
||||
unsigned int CUnBitArray::DecodeValue(DECODE_VALUE_METHOD DecodeMethod, int nParam1, int nParam2)
|
||||
{
|
||||
switch (DecodeMethod)
|
||||
{
|
||||
case DECODE_VALUE_METHOD_UNSIGNED_INT:
|
||||
return DecodeValueXBits(32);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void CUnBitArray::GenerateArray(int *pOutputArray, int nElements, int nBytesRequired)
|
||||
{
|
||||
GenerateArrayRange(pOutputArray, nElements);
|
||||
}
|
||||
|
||||
__inline unsigned char CUnBitArray::GetC()
|
||||
{
|
||||
unsigned char nValue = (unsigned char) (m_pBitArray[m_nCurrentBitIndex >> 5] >> (24 - (m_nCurrentBitIndex & 31)));
|
||||
m_nCurrentBitIndex += 8;
|
||||
return nValue;
|
||||
}
|
||||
|
||||
__inline int CUnBitArray::RangeDecodeFast(int nShift)
|
||||
{
|
||||
while (m_RangeCoderInfo.range <= BOTTOM_VALUE)
|
||||
{
|
||||
m_RangeCoderInfo.buffer = (m_RangeCoderInfo.buffer << 8) | ((m_pBitArray[m_nCurrentBitIndex >> 5] >> (24 - (m_nCurrentBitIndex & 31))) & 0xFF);
|
||||
m_nCurrentBitIndex += 8;
|
||||
m_RangeCoderInfo.low = (m_RangeCoderInfo.low << 8) | ((m_RangeCoderInfo.buffer >> 1) & 0xFF);
|
||||
m_RangeCoderInfo.range <<= 8;
|
||||
}
|
||||
|
||||
// decode
|
||||
m_RangeCoderInfo.range = m_RangeCoderInfo.range >> nShift;
|
||||
return m_RangeCoderInfo.low / m_RangeCoderInfo.range;
|
||||
}
|
||||
|
||||
__inline int CUnBitArray::RangeDecodeFastWithUpdate(int nShift)
|
||||
{
|
||||
while (m_RangeCoderInfo.range <= BOTTOM_VALUE)
|
||||
{
|
||||
m_RangeCoderInfo.buffer = (m_RangeCoderInfo.buffer << 8) | ((m_pBitArray[m_nCurrentBitIndex >> 5] >> (24 - (m_nCurrentBitIndex & 31))) & 0xFF);
|
||||
m_nCurrentBitIndex += 8;
|
||||
m_RangeCoderInfo.low = (m_RangeCoderInfo.low << 8) | ((m_RangeCoderInfo.buffer >> 1) & 0xFF);
|
||||
m_RangeCoderInfo.range <<= 8;
|
||||
}
|
||||
|
||||
// decode
|
||||
m_RangeCoderInfo.range = m_RangeCoderInfo.range >> nShift;
|
||||
int nRetVal = m_RangeCoderInfo.low / m_RangeCoderInfo.range;
|
||||
m_RangeCoderInfo.low -= m_RangeCoderInfo.range * nRetVal;
|
||||
return nRetVal;
|
||||
}
|
||||
|
||||
int CUnBitArray::DecodeValueRange(BIT_ARRAY_STATE & BitArrayState)
|
||||
{
|
||||
// make sure there is room for the data
|
||||
// this is a little slower than ensuring a huge block to start with, but it's safer
|
||||
if (m_nCurrentBitIndex > m_nRefillBitThreshold)
|
||||
{
|
||||
FillBitArray();
|
||||
}
|
||||
|
||||
// decode
|
||||
int nRangeTotal = RangeDecodeFast(RANGE_OVERFLOW_SHIFT);
|
||||
|
||||
// lookup the symbol (must be a faster way than this)
|
||||
int nOverflow = 0;
|
||||
while (nRangeTotal >= RANGE_TOTAL[nOverflow + 1]) { nOverflow++; }
|
||||
|
||||
// update
|
||||
m_RangeCoderInfo.low -= m_RangeCoderInfo.range * RANGE_TOTAL[nOverflow];
|
||||
m_RangeCoderInfo.range = m_RangeCoderInfo.range * RANGE_WIDTH[nOverflow];
|
||||
|
||||
// get the working k
|
||||
int nTempK;
|
||||
if (nOverflow == (MODEL_ELEMENTS - 1))
|
||||
{
|
||||
nTempK = RangeDecodeFastWithUpdate(5);
|
||||
nOverflow = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
nTempK = (BitArrayState.k < 1) ? 0 : BitArrayState.k - 1;
|
||||
}
|
||||
|
||||
// get the value (k bits)
|
||||
int nValue;
|
||||
|
||||
// figure the extra bits on the left and the left value
|
||||
if (nTempK <= 16 || m_nVersion < 3910)
|
||||
{
|
||||
nValue = RangeDecodeFastWithUpdate(nTempK);
|
||||
}
|
||||
else
|
||||
{
|
||||
int nX1 = RangeDecodeFastWithUpdate(16);
|
||||
int nX2 = RangeDecodeFastWithUpdate(nTempK - 16);
|
||||
nValue = nX1 | (nX2 << 16);
|
||||
}
|
||||
|
||||
// build the value and output it
|
||||
nValue += (nOverflow << nTempK);
|
||||
|
||||
// update nKSum
|
||||
BitArrayState.nKSum += ((nValue + 1) / 2) - ((BitArrayState.nKSum + 16) >> 5);
|
||||
|
||||
// update k
|
||||
if (BitArrayState.nKSum < K_SUM_MIN_BOUNDARY[BitArrayState.k])
|
||||
BitArrayState.k--;
|
||||
else if (BitArrayState.nKSum >= K_SUM_MIN_BOUNDARY[BitArrayState.k + 1])
|
||||
BitArrayState.k++;
|
||||
|
||||
// output the value (converted to signed)
|
||||
return (nValue & 1) ? (nValue >> 1) + 1 : -(nValue >> 1);
|
||||
}
|
||||
|
||||
void CUnBitArray::FlushState(BIT_ARRAY_STATE & BitArrayState)
|
||||
{
|
||||
BitArrayState.k = 10;
|
||||
BitArrayState.nKSum = (1 << BitArrayState.k) * 16;
|
||||
}
|
||||
|
||||
void CUnBitArray::FlushBitArray()
|
||||
{
|
||||
AdvanceToByteBoundary();
|
||||
m_nCurrentBitIndex += 8; // ignore the first byte... (slows compression too much to not output this dummy byte)
|
||||
m_RangeCoderInfo.buffer = GetC();
|
||||
m_RangeCoderInfo.low = m_RangeCoderInfo.buffer >> (8 - EXTRA_BITS);
|
||||
m_RangeCoderInfo.range = (unsigned int) 1 << EXTRA_BITS;
|
||||
|
||||
m_nRefillBitThreshold = (m_nBits - 512);
|
||||
}
|
||||
|
||||
void CUnBitArray::Finalize()
|
||||
{
|
||||
// normalize
|
||||
while (m_RangeCoderInfo.range <= BOTTOM_VALUE)
|
||||
{
|
||||
m_nCurrentBitIndex += 8;
|
||||
m_RangeCoderInfo.range <<= 8;
|
||||
}
|
||||
|
||||
// used to back-pedal the last two bytes out
|
||||
// this should never have been a problem because we've outputted and normalized beforehand
|
||||
// but stopped doing it as of 3.96 in case it accounted for rare decompression failures
|
||||
if (m_nVersion <= 3950)
|
||||
m_nCurrentBitIndex -= 16;
|
||||
}
|
||||
|
||||
void CUnBitArray::GenerateArrayRange(int *pOutputArray, int nElements)
|
||||
{
|
||||
BIT_ARRAY_STATE BitArrayState;
|
||||
FlushState(BitArrayState);
|
||||
FlushBitArray();
|
||||
|
||||
for (int z = 0; z < nElements; z++)
|
||||
{
|
||||
pOutputArray[z] = DecodeValueRange(BitArrayState);
|
||||
}
|
||||
|
||||
Finalize();
|
||||
}
|
54
gst/monkeyaudio/libmonkeyaudio/UnBitArray.h
Normal file
54
gst/monkeyaudio/libmonkeyaudio/UnBitArray.h
Normal file
|
@ -0,0 +1,54 @@
|
|||
#ifndef UNBITARRAY_H
|
||||
#define UNBITARRAY_H
|
||||
|
||||
#include "UnBitArrayBase.h"
|
||||
#include "BitArray.h"
|
||||
|
||||
class IAPEDecompress;
|
||||
|
||||
struct RANGE_CODER_STRUCT_DECOMPRESS
|
||||
{
|
||||
unsigned int low; //low end of interval
|
||||
unsigned int range; //length of interval
|
||||
unsigned int buffer; //buffer for input/output
|
||||
};
|
||||
|
||||
class CUnBitArray : public CUnBitArrayBase
|
||||
{
|
||||
|
||||
public:
|
||||
//construction/destruction
|
||||
CUnBitArray(IAPEDecompress *pAPEInfo, int nVersion);
|
||||
~CUnBitArray();
|
||||
|
||||
unsigned int DecodeValue(DECODE_VALUE_METHOD DecodeMethod, int nParam1 = 0, int nParam2 = 0);
|
||||
|
||||
void GenerateArray(int *pOutputArray, int nElements, int nBytesRequired = -1);
|
||||
|
||||
int DecodeValueRange(BIT_ARRAY_STATE & BitArrayState);
|
||||
|
||||
void FlushState(BIT_ARRAY_STATE & BitArrayState);
|
||||
void FlushBitArray();
|
||||
void Finalize();
|
||||
|
||||
private:
|
||||
|
||||
void GenerateArrayRange(int *pOutputArray, int nElements);
|
||||
|
||||
//data
|
||||
int m_nFlushCounter;
|
||||
int m_nFinalizeCounter;
|
||||
|
||||
RANGE_CODER_STRUCT_DECOMPRESS m_RangeCoderInfo;
|
||||
|
||||
unsigned __int32 m_nRefillBitThreshold;
|
||||
|
||||
//functions
|
||||
__inline int RangeDecodeFast(int nShift);
|
||||
__inline int RangeDecodeFastWithUpdate(int nShift);
|
||||
__inline unsigned char GetC();
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif /* UNBITARRAY_H */
|
118
gst/monkeyaudio/libmonkeyaudio/UnBitArrayBase.cpp
Normal file
118
gst/monkeyaudio/libmonkeyaudio/UnBitArrayBase.cpp
Normal file
|
@ -0,0 +1,118 @@
|
|||
#include "All.h"
|
||||
#include "UnBitArrayBase.h"
|
||||
#include "APEInfo.h"
|
||||
#include "UnBitArray.h"
|
||||
#ifdef BACKWARDS_COMPATIBILITY
|
||||
#include "Old/APEDecompressOld.h"
|
||||
#include "Old/UnBitArrayOld.h"
|
||||
#endif
|
||||
|
||||
const unsigned __int32 POWERS_OF_TWO_MINUS_ONE[33] = {0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535,131071,262143,524287,1048575,2097151,4194303,8388607,16777215,33554431,67108863,134217727,268435455,536870911,1073741823,2147483647,4294967295LU};
|
||||
|
||||
CUnBitArrayBase * CreateUnBitArray(IAPEDecompress *pAPEDecompress, int nVersion)
|
||||
{
|
||||
#ifdef BACKWARDS_COMPATIBILITY
|
||||
if (nVersion >= 3900)
|
||||
return (CUnBitArrayBase * ) new CUnBitArray(pAPEDecompress, nVersion);
|
||||
else
|
||||
return (CUnBitArrayBase * ) new CUnBitArrayOld(pAPEDecompress, nVersion);
|
||||
#else
|
||||
return (CUnBitArrayBase * ) new CUnBitArray(pAPEDecompress, nVersion);
|
||||
#endif
|
||||
}
|
||||
|
||||
void CUnBitArrayBase::AdvanceToByteBoundary()
|
||||
{
|
||||
#if 0
|
||||
m_nCurrentBitIndex--;
|
||||
m_nCurrentBitIndex |= 7;
|
||||
m_nCurrentBitIndex++;
|
||||
#else
|
||||
int nMod = m_nCurrentBitIndex % 8;
|
||||
if (nMod != 0) { m_nCurrentBitIndex += 8 - nMod; }
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned __int32 CUnBitArrayBase::DecodeValueXBits(unsigned __int32 nBits)
|
||||
{
|
||||
//get more data if necessary
|
||||
if ((m_nCurrentBitIndex + nBits) >= m_nBits)
|
||||
FillBitArray();
|
||||
|
||||
//variable declares
|
||||
unsigned __int32 nLeftBits = 32 - (m_nCurrentBitIndex & 31);
|
||||
unsigned __int32 nBitArrayIndex = m_nCurrentBitIndex >> 5;
|
||||
m_nCurrentBitIndex += nBits;
|
||||
|
||||
//if their isn't an overflow to the right value, get the value and exit
|
||||
if (nLeftBits >= nBits)
|
||||
return (m_pBitArray[nBitArrayIndex] & (POWERS_OF_TWO_MINUS_ONE[nLeftBits])) >> (nLeftBits - nBits);
|
||||
|
||||
//must get the "split" value from left and right
|
||||
int nRightBits = nBits - nLeftBits;
|
||||
|
||||
unsigned __int32 nLeftValue = ((m_pBitArray[nBitArrayIndex] & POWERS_OF_TWO_MINUS_ONE[nLeftBits]) << nRightBits);
|
||||
unsigned __int32 nRightValue = (m_pBitArray[nBitArrayIndex + 1] >> (32 - nRightBits));
|
||||
return (nLeftValue | nRightValue);
|
||||
}
|
||||
|
||||
int CUnBitArrayBase::FillAndResetBitArray(int nFileLocation, int nNewBitIndex)
|
||||
{
|
||||
//reset the bit index
|
||||
m_nCurrentBitIndex = nNewBitIndex;
|
||||
|
||||
//seek if necessary
|
||||
if (nFileLocation != -1)
|
||||
{
|
||||
if (GET_IO(m_pAPEDecompress)->Seek(nFileLocation, FILE_BEGIN) != 0)
|
||||
return ERROR_IO_READ;
|
||||
}
|
||||
|
||||
//read the new data into the bit array
|
||||
unsigned int nBytesRead = 0;
|
||||
if (GET_IO(m_pAPEDecompress)->Read(((unsigned char *) m_pBitArray), m_nBytes, &nBytesRead) != 0)
|
||||
return ERROR_IO_READ;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CUnBitArrayBase::FillBitArray()
|
||||
{
|
||||
//get the bit array index
|
||||
unsigned __int32 nBitArrayIndex = m_nCurrentBitIndex >> 5;
|
||||
|
||||
//move the remaining data to the front
|
||||
memmove((void *) (m_pBitArray), (const void *) (m_pBitArray + nBitArrayIndex), m_nBytes - (nBitArrayIndex * 4));
|
||||
|
||||
//read the new data
|
||||
int nBytesToRead = nBitArrayIndex * 4;
|
||||
unsigned int nBytesRead = 0;
|
||||
int nRetVal = GET_IO(m_pAPEDecompress)->Read((unsigned char *) (m_pBitArray + m_nElements - nBitArrayIndex), nBytesToRead, &nBytesRead);
|
||||
|
||||
//adjust the m_Bit pointer
|
||||
m_nCurrentBitIndex = m_nCurrentBitIndex & 31;
|
||||
|
||||
//return
|
||||
return (nRetVal == 0) ? 0 : ERROR_IO_READ;
|
||||
}
|
||||
|
||||
int CUnBitArrayBase::CreateHelper(IAPEDecompress *pAPEDecompress, int nBytes, int nVersion)
|
||||
{
|
||||
//check the parameters
|
||||
if ((pAPEDecompress == NULL) || (nBytes <= 0)) { return ERROR_BAD_PARAMETER; }
|
||||
|
||||
//save the size
|
||||
m_nElements = nBytes / 4;
|
||||
m_nBytes = m_nElements * 4;
|
||||
m_nBits = m_nBytes * 8;
|
||||
|
||||
//set the variables
|
||||
m_pAPEDecompress = pAPEDecompress;
|
||||
m_nVersion = nVersion;
|
||||
m_nCurrentBitIndex = 0;
|
||||
|
||||
//create the bitarray
|
||||
m_pBitArray = new unsigned __int32 [m_nElements];
|
||||
|
||||
return (m_pBitArray != NULL) ? 0 : ERROR_INSUFFICIENT_MEMORY;
|
||||
}
|
54
gst/monkeyaudio/libmonkeyaudio/UnBitArrayBase.h
Normal file
54
gst/monkeyaudio/libmonkeyaudio/UnBitArrayBase.h
Normal file
|
@ -0,0 +1,54 @@
|
|||
#ifndef UNBITARRAYBASE_H
|
||||
#define UNBITARRAYBASE_H
|
||||
|
||||
class IAPEDecompress;
|
||||
#include "BitArray.h"
|
||||
|
||||
enum DECODE_VALUE_METHOD
|
||||
{
|
||||
DECODE_VALUE_METHOD_UNSIGNED_INT,
|
||||
DECODE_VALUE_METHOD_UNSIGNED_RICE,
|
||||
DECODE_VALUE_METHOD_X_BITS
|
||||
};
|
||||
|
||||
class CUnBitArrayBase
|
||||
{
|
||||
public:
|
||||
|
||||
//construction/destruction
|
||||
CUnBitArrayBase(IAPEDecompress *pAPEDecompress, int nVersion) {}
|
||||
virtual ~CUnBitArrayBase() {}
|
||||
|
||||
//functions
|
||||
virtual int FillBitArray();
|
||||
virtual int FillAndResetBitArray(int nFileLocation = -1, int nNewBitIndex = 0);
|
||||
|
||||
virtual void GenerateArray(int *pOutputArray, int nElements, int nBytesRequired = -1) {}
|
||||
virtual unsigned int DecodeValue(DECODE_VALUE_METHOD DecodeMethod, int nParam1 = 0, int nParam2 = 0) { return 0; }
|
||||
|
||||
virtual void AdvanceToByteBoundary();
|
||||
|
||||
virtual int DecodeValueRange(BIT_ARRAY_STATE & BitArrayState) { return 0; }
|
||||
virtual void FlushState(BIT_ARRAY_STATE & BitArrayState) {}
|
||||
virtual void FlushBitArray() {}
|
||||
virtual void Finalize() {}
|
||||
|
||||
protected:
|
||||
|
||||
virtual int CreateHelper(IAPEDecompress *pAPEDecompress, int nBytes, int nVersion);
|
||||
virtual unsigned __int32 DecodeValueXBits(unsigned __int32 nBits);
|
||||
|
||||
unsigned __int32 m_nElements;
|
||||
unsigned __int32 m_nBytes;
|
||||
unsigned __int32 m_nBits;
|
||||
|
||||
int m_nVersion;
|
||||
IAPEDecompress * m_pAPEDecompress;
|
||||
|
||||
unsigned __int32 m_nCurrentBitIndex;
|
||||
unsigned __int32 *m_pBitArray;
|
||||
};
|
||||
|
||||
CUnBitArrayBase * CreateUnBitArray(IAPEDecompress * pAPEDecompress, int nVersion);
|
||||
|
||||
#endif /* UNBITARRAYBASE_H */
|
283
gst/monkeyaudio/libmonkeyaudio/WAVInputSource.cpp
Normal file
283
gst/monkeyaudio/libmonkeyaudio/WAVInputSource.cpp
Normal file
|
@ -0,0 +1,283 @@
|
|||
#include "All.h"
|
||||
#include "WAVInputSource.h"
|
||||
#include IO_HEADER_FILE
|
||||
#include "MACLib.h"
|
||||
#include "GlobalFunctions.h"
|
||||
|
||||
struct RIFF_HEADER
|
||||
{
|
||||
char cRIFF[4]; // the characters 'RIFF' indicating that it's a RIFF file
|
||||
unsigned long nBytes; // the number of bytes following this header
|
||||
};
|
||||
|
||||
struct DATA_TYPE_ID_HEADER
|
||||
{
|
||||
char cDataTypeID[4]; // should equal 'WAVE' for a WAV file
|
||||
};
|
||||
|
||||
struct WAV_FORMAT_HEADER
|
||||
{
|
||||
unsigned short nFormatTag; // the format of the WAV...should equal 1 for a PCM file
|
||||
unsigned short nChannels; // the number of channels
|
||||
unsigned long nSamplesPerSecond; // the number of samples per second
|
||||
unsigned long nBytesPerSecond; // the bytes per second
|
||||
unsigned short nBlockAlign; // block alignment
|
||||
unsigned short nBitsPerSample; // the number of bits per sample
|
||||
};
|
||||
|
||||
struct RIFF_CHUNK_HEADER
|
||||
{
|
||||
char cChunkLabel[4]; // should equal "data" indicating the data chunk
|
||||
unsigned long nChunkBytes; // the bytes of the chunk
|
||||
};
|
||||
|
||||
|
||||
CInputSource * CreateInputSource(const char * pSourceName, WAVEFORMATEX * pwfeSource, int * pTotalBlocks, int * pHeaderBytes, int * pTerminatingBytes, int * pErrorCode)
|
||||
{
|
||||
// error check the parameters
|
||||
if ((pSourceName == NULL) || (strlen(pSourceName) == 0))
|
||||
{
|
||||
if (pErrorCode) *pErrorCode = ERROR_BAD_PARAMETER;
|
||||
return NULL;
|
||||
}
|
||||
// Removed bad code which avoid compressing of files if extention is not standard
|
||||
#if 0
|
||||
// get the extension
|
||||
const char * pExtension = &pSourceName[strlen(pSourceName)];
|
||||
while ((pExtension > pSourceName) && (*pExtension != '.'))
|
||||
pExtension--;
|
||||
|
||||
// create the proper input source
|
||||
if (_stricmp(pExtension, ".wav") == 0)
|
||||
{
|
||||
if (pErrorCode) *pErrorCode = ERROR_SUCCESS;
|
||||
#endif
|
||||
return new CWAVInputSource(pSourceName, pwfeSource, pTotalBlocks, pHeaderBytes, pTerminatingBytes, pErrorCode);
|
||||
#if 0
|
||||
}
|
||||
else
|
||||
{
|
||||
if (pErrorCode) *pErrorCode = ERROR_INVALID_INPUT_FILE;
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
CWAVInputSource::CWAVInputSource(CIO * pIO, WAVEFORMATEX * pwfeSource, int * pTotalBlocks, int * pHeaderBytes, int * pTerminatingBytes, int * pErrorCode)
|
||||
: CInputSource(pIO, pwfeSource, pTotalBlocks, pHeaderBytes, pTerminatingBytes, pErrorCode)
|
||||
{
|
||||
m_bIsValid = FALSE;
|
||||
|
||||
if (pIO == NULL || pwfeSource == NULL)
|
||||
{
|
||||
if (pErrorCode) *pErrorCode = ERROR_BAD_PARAMETER;
|
||||
return;
|
||||
}
|
||||
|
||||
m_spIO.Assign(pIO, FALSE, FALSE);
|
||||
|
||||
int nRetVal = AnalyzeSource();
|
||||
if (nRetVal == ERROR_SUCCESS)
|
||||
{
|
||||
// fill in the parameters
|
||||
if (pwfeSource) memcpy(pwfeSource, &m_wfeSource, sizeof(WAVEFORMATEX));
|
||||
if (pTotalBlocks) *pTotalBlocks = m_nDataBytes / m_wfeSource.nBlockAlign;
|
||||
if (pHeaderBytes) *pHeaderBytes = m_nHeaderBytes;
|
||||
if (pTerminatingBytes) *pTerminatingBytes = m_nTerminatingBytes;
|
||||
|
||||
m_bIsValid = TRUE;
|
||||
}
|
||||
|
||||
if (pErrorCode) *pErrorCode = nRetVal;
|
||||
}
|
||||
|
||||
CWAVInputSource::CWAVInputSource(const char * pSourceName, WAVEFORMATEX * pwfeSource, int * pTotalBlocks, int * pHeaderBytes, int * pTerminatingBytes, int * pErrorCode)
|
||||
: CInputSource(pSourceName, pwfeSource, pTotalBlocks, pHeaderBytes, pTerminatingBytes, pErrorCode)
|
||||
{
|
||||
m_bIsValid = FALSE;
|
||||
|
||||
if (pSourceName == NULL || pwfeSource == NULL)
|
||||
{
|
||||
if (pErrorCode) *pErrorCode = ERROR_BAD_PARAMETER;
|
||||
return;
|
||||
}
|
||||
|
||||
m_spIO.Assign(new IO_CLASS_NAME);
|
||||
if (m_spIO->Open(pSourceName) != ERROR_SUCCESS)
|
||||
{
|
||||
m_spIO.Delete();
|
||||
if (pErrorCode) *pErrorCode = ERROR_INVALID_INPUT_FILE;
|
||||
return;
|
||||
}
|
||||
|
||||
int nRetVal = AnalyzeSource();
|
||||
if (nRetVal == ERROR_SUCCESS)
|
||||
{
|
||||
// fill in the parameters
|
||||
if (pwfeSource) memcpy(pwfeSource, &m_wfeSource, sizeof(WAVEFORMATEX));
|
||||
if (pTotalBlocks) *pTotalBlocks = m_nDataBytes / m_wfeSource.nBlockAlign;
|
||||
if (pHeaderBytes) *pHeaderBytes = m_nHeaderBytes;
|
||||
if (pTerminatingBytes) *pTerminatingBytes = m_nTerminatingBytes;
|
||||
|
||||
m_bIsValid = TRUE;
|
||||
}
|
||||
|
||||
if (pErrorCode) *pErrorCode = nRetVal;
|
||||
}
|
||||
|
||||
CWAVInputSource::~CWAVInputSource()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
int CWAVInputSource::AnalyzeSource()
|
||||
{
|
||||
// seek to the beginning (just in case)
|
||||
m_spIO->Seek(0, FILE_BEGIN);
|
||||
|
||||
// get the file size
|
||||
m_nFileBytes = m_spIO->GetSize();
|
||||
|
||||
// get the RIFF header
|
||||
RIFF_HEADER RIFFHeader;
|
||||
RETURN_ON_ERROR(ReadSafe(m_spIO, &RIFFHeader, sizeof(RIFFHeader)))
|
||||
|
||||
// make sure the RIFF header is valid
|
||||
if (!(RIFFHeader.cRIFF[0] == 'R' && RIFFHeader.cRIFF[1] == 'I' && RIFFHeader.cRIFF[2] == 'F' && RIFFHeader.cRIFF[3] == 'F'))
|
||||
return ERROR_INVALID_INPUT_FILE;
|
||||
|
||||
// read the data type header
|
||||
DATA_TYPE_ID_HEADER DataTypeIDHeader;
|
||||
RETURN_ON_ERROR(ReadSafe(m_spIO, &DataTypeIDHeader, sizeof(DataTypeIDHeader)))
|
||||
|
||||
// make sure it's the right data type
|
||||
if (!(DataTypeIDHeader.cDataTypeID[0] == 'W' && DataTypeIDHeader.cDataTypeID[1] == 'A' && DataTypeIDHeader.cDataTypeID[2] == 'V' && DataTypeIDHeader.cDataTypeID[3] == 'E'))
|
||||
return ERROR_INVALID_INPUT_FILE;
|
||||
|
||||
// find the 'fmt ' chunk
|
||||
RIFF_CHUNK_HEADER RIFFChunkHeader;
|
||||
RETURN_ON_ERROR(ReadSafe(m_spIO, &RIFFChunkHeader, sizeof(RIFFChunkHeader)))
|
||||
|
||||
while (!(RIFFChunkHeader.cChunkLabel[0] == 'f' && RIFFChunkHeader.cChunkLabel[1] == 'm' && RIFFChunkHeader.cChunkLabel[2] == 't' && RIFFChunkHeader.cChunkLabel[3] == ' '))
|
||||
{
|
||||
// move the file pointer to the end of this chunk
|
||||
m_spIO->Seek(RIFFChunkHeader.nChunkBytes, FILE_CURRENT);
|
||||
|
||||
// check again for the data chunk
|
||||
RETURN_ON_ERROR(ReadSafe(m_spIO, &RIFFChunkHeader, sizeof(RIFFChunkHeader)))
|
||||
}
|
||||
|
||||
// read the format info
|
||||
WAV_FORMAT_HEADER WAVFormatHeader;
|
||||
RETURN_ON_ERROR(ReadSafe(m_spIO, &WAVFormatHeader, sizeof(WAVFormatHeader)))
|
||||
|
||||
// error check the header to see if we support it
|
||||
if (WAVFormatHeader.nFormatTag != 1)
|
||||
return ERROR_INVALID_INPUT_FILE;
|
||||
|
||||
// copy the format information to the WAVEFORMATEX passed in
|
||||
FillWaveFormatEx(&m_wfeSource, WAVFormatHeader.nSamplesPerSecond, WAVFormatHeader.nBitsPerSample, WAVFormatHeader.nChannels);
|
||||
|
||||
// skip over any extra data in the header
|
||||
int nWAVFormatHeaderExtra = RIFFChunkHeader.nChunkBytes - sizeof(WAVFormatHeader);
|
||||
if (nWAVFormatHeaderExtra < 0)
|
||||
return ERROR_INVALID_INPUT_FILE;
|
||||
else
|
||||
//m_spIO->Seek(nWAVFormatHeaderExtra, FILE_CURRENT);
|
||||
|
||||
// find the data chunk
|
||||
RETURN_ON_ERROR(ReadSafe(m_spIO, &RIFFChunkHeader, sizeof(RIFFChunkHeader)))
|
||||
|
||||
while (!(RIFFChunkHeader.cChunkLabel[0] == 'd' && RIFFChunkHeader.cChunkLabel[1] == 'a' && RIFFChunkHeader.cChunkLabel[2] == 't' && RIFFChunkHeader.cChunkLabel[3] == 'a'))
|
||||
{
|
||||
// move the file pointer to the end of this chunk
|
||||
m_spIO->Seek(RIFFChunkHeader.nChunkBytes, FILE_CURRENT);
|
||||
|
||||
// check again for the data chunk
|
||||
RETURN_ON_ERROR(ReadSafe(m_spIO, &RIFFChunkHeader, sizeof(RIFFChunkHeader)))
|
||||
}
|
||||
|
||||
// we're at the data block
|
||||
m_nHeaderBytes = m_spIO->GetPosition();
|
||||
m_nDataBytes = RIFFChunkHeader.nChunkBytes;
|
||||
if (m_nDataBytes < 0)
|
||||
m_nDataBytes = m_nFileBytes - m_nHeaderBytes;
|
||||
|
||||
// make sure the data bytes is a whole number of blocks
|
||||
if ((m_nDataBytes % m_wfeSource.nBlockAlign) != 0)
|
||||
return ERROR_INVALID_INPUT_FILE;
|
||||
|
||||
// calculate the terminating byts
|
||||
m_nTerminatingBytes = m_nFileBytes - m_nDataBytes - m_nHeaderBytes;
|
||||
|
||||
// we made it this far, everything must be cool
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
int CWAVInputSource::GetData(unsigned char * pBuffer, int nBlocks, int * pBlocksRetrieved)
|
||||
{
|
||||
if (!m_bIsValid) return ERROR_UNDEFINED;
|
||||
|
||||
int nBytes = (m_wfeSource.nBlockAlign * nBlocks);
|
||||
unsigned int nBytesRead = 0;
|
||||
|
||||
if (m_spIO->Read(pBuffer, nBytes, &nBytesRead) != ERROR_SUCCESS)
|
||||
return ERROR_IO_READ;
|
||||
|
||||
if (pBlocksRetrieved) *pBlocksRetrieved = (nBytesRead / m_wfeSource.nBlockAlign);
|
||||
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
int CWAVInputSource::GetHeaderData(unsigned char * pBuffer)
|
||||
{
|
||||
if (!m_bIsValid) return ERROR_UNDEFINED;
|
||||
|
||||
int nRetVal = ERROR_SUCCESS;
|
||||
|
||||
if (m_nHeaderBytes > 0)
|
||||
{
|
||||
int nOriginalFileLocation = m_spIO->GetPosition();
|
||||
|
||||
m_spIO->Seek(0, FILE_BEGIN);
|
||||
|
||||
unsigned int nBytesRead = 0;
|
||||
int nReadRetVal = m_spIO->Read(pBuffer, m_nHeaderBytes, &nBytesRead);
|
||||
|
||||
if ((nReadRetVal != ERROR_SUCCESS) || (m_nHeaderBytes != int(nBytesRead)))
|
||||
{
|
||||
nRetVal = ERROR_UNDEFINED;
|
||||
}
|
||||
|
||||
m_spIO->Seek(nOriginalFileLocation, FILE_BEGIN);
|
||||
}
|
||||
|
||||
return nRetVal;
|
||||
}
|
||||
|
||||
int CWAVInputSource::GetTerminatingData(unsigned char * pBuffer)
|
||||
{
|
||||
if (!m_bIsValid) return ERROR_UNDEFINED;
|
||||
|
||||
int nRetVal = ERROR_SUCCESS;
|
||||
|
||||
if (m_nTerminatingBytes > 0)
|
||||
{
|
||||
int nOriginalFileLocation = m_spIO->GetPosition();
|
||||
|
||||
m_spIO->Seek(-m_nTerminatingBytes, FILE_END);
|
||||
|
||||
unsigned int nBytesRead = 0;
|
||||
int nReadRetVal = m_spIO->Read(pBuffer, m_nTerminatingBytes, &nBytesRead);
|
||||
|
||||
if ((nReadRetVal != ERROR_SUCCESS) || (m_nTerminatingBytes != int(nBytesRead)))
|
||||
{
|
||||
nRetVal = ERROR_UNDEFINED;
|
||||
}
|
||||
|
||||
m_spIO->Seek(nOriginalFileLocation, FILE_BEGIN);
|
||||
}
|
||||
|
||||
return nRetVal;
|
||||
}
|
64
gst/monkeyaudio/libmonkeyaudio/WAVInputSource.h
Normal file
64
gst/monkeyaudio/libmonkeyaudio/WAVInputSource.h
Normal file
|
@ -0,0 +1,64 @@
|
|||
#ifndef APE_WAVEINPUTSOURCE_H
|
||||
#define APE_WAVEINPUTSOURCE_H
|
||||
|
||||
#include "IO.h"
|
||||
|
||||
/*************************************************************************************
|
||||
CInputSource - base input format class... allows multiple format support
|
||||
*************************************************************************************/
|
||||
class CInputSource
|
||||
{
|
||||
public:
|
||||
|
||||
// construction / destruction
|
||||
CInputSource(CIO * pIO, WAVEFORMATEX * pwfeSource, int * pTotalBlocks, int * pHeaderBytes, int * pTerminatingBytes, int * pErrorCode = NULL) { }
|
||||
CInputSource(const char * pSourceName, WAVEFORMATEX * pwfeSource, int * pTotalBlocks, int * pHeaderBytes, int * pTerminatingBytes, int * pErrorCode = NULL) { }
|
||||
virtual ~CInputSource() { }
|
||||
|
||||
// get data
|
||||
virtual int GetData(unsigned char * pBuffer, int nBlocks, int * pBlocksRetrieved) = 0;
|
||||
|
||||
// get header / terminating data
|
||||
virtual int GetHeaderData(unsigned char * pBuffer) = 0;
|
||||
virtual int GetTerminatingData(unsigned char * pBuffer) = 0;
|
||||
};
|
||||
|
||||
/*************************************************************************************
|
||||
CWAVInputSource - wraps working with WAV files (could be extended to any format)
|
||||
*************************************************************************************/
|
||||
class CWAVInputSource : public CInputSource
|
||||
{
|
||||
public:
|
||||
|
||||
// construction / destruction
|
||||
CWAVInputSource(CIO * pIO, WAVEFORMATEX * pwfeSource, int * pTotalBlocks, int * pHeaderBytes, int * pTerminatingBytes, int * pErrorCode = NULL);
|
||||
CWAVInputSource(const char * pSourceName, WAVEFORMATEX * pwfeSource, int * pTotalBlocks, int * pHeaderBytes, int * pTerminatingBytes, int * pErrorCode = NULL);
|
||||
~CWAVInputSource();
|
||||
|
||||
// get data
|
||||
int GetData(unsigned char * pBuffer, int nBlocks, int * pBlocksRetrieved);
|
||||
|
||||
// get header / terminating data
|
||||
int GetHeaderData(unsigned char * pBuffer);
|
||||
int GetTerminatingData(unsigned char * pBuffer);
|
||||
|
||||
private:
|
||||
|
||||
int AnalyzeSource();
|
||||
|
||||
CSmartPtr<CIO> m_spIO;
|
||||
|
||||
WAVEFORMATEX m_wfeSource;
|
||||
int m_nHeaderBytes;
|
||||
int m_nDataBytes;
|
||||
int m_nTerminatingBytes;
|
||||
int m_nFileBytes;
|
||||
BOOL m_bIsValid;
|
||||
};
|
||||
|
||||
/*************************************************************************************
|
||||
Input souce creation
|
||||
*************************************************************************************/
|
||||
CInputSource * CreateInputSource(const char * pSourceName, WAVEFORMATEX * pwfeSource, int * pTotalBlocks, int * pHeaderBytes, int * pTerminatingBytes, int * pErrorCode = NULL);
|
||||
|
||||
#endif /* APE_WAVEINPUTSOURCE_H */
|
268
gst/monkeyaudio/monkey_io.cc
Normal file
268
gst/monkeyaudio/monkey_io.cc
Normal file
|
@ -0,0 +1,268 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library 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.
|
||||
*/
|
||||
|
||||
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include "monkey_io.h"
|
||||
|
||||
sinkpad_CIO::sinkpad_CIO (void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int sinkpad_CIO::Open (const char * pName)
|
||||
{
|
||||
position = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int sinkpad_CIO::GetName (char * pBuffer)
|
||||
{
|
||||
strcpy (pBuffer, "");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sinkpad_CIO::GetSize ()
|
||||
{
|
||||
return gst_bytestream_length (bs);
|
||||
}
|
||||
|
||||
int sinkpad_CIO::GetPosition ()
|
||||
{
|
||||
return gst_bytestream_tell (bs);
|
||||
}
|
||||
|
||||
int sinkpad_CIO::SetEOF ()
|
||||
{
|
||||
/* FIXME, hack, pull final EOS from peer */
|
||||
gst_bytestream_flush (bs, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sinkpad_CIO::Close ()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sinkpad_CIO::Read(void * pBuffer, unsigned int nBytesToRead, unsigned int * pBytesRead)
|
||||
{
|
||||
guint insize = 0;
|
||||
guint8 *indata;
|
||||
|
||||
while (insize == 0) {
|
||||
insize = gst_bytestream_peek_bytes (bs, &indata, nBytesToRead);
|
||||
if (insize < nBytesToRead) {
|
||||
GstEvent *event;
|
||||
guint32 avail;
|
||||
|
||||
gst_bytestream_get_status (bs, &avail, &event);
|
||||
|
||||
switch (GST_EVENT_TYPE (event)) {
|
||||
case GST_EVENT_EOS:
|
||||
GST_DEBUG (0, "eos");
|
||||
eos = TRUE;
|
||||
gst_event_unref (event);
|
||||
if (avail == 0) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case GST_EVENT_DISCONTINUOUS:
|
||||
GST_DEBUG (0, "discont");
|
||||
/* we are not yet sending the discont, we'll do that in the next write operation */
|
||||
need_discont = TRUE;
|
||||
gst_event_unref (event);
|
||||
break;
|
||||
default:
|
||||
gst_pad_event_default (sinkpad, event);
|
||||
break;
|
||||
}
|
||||
|
||||
if (avail > 0)
|
||||
insize = gst_bytestream_peek_bytes (bs, &indata, avail);
|
||||
else
|
||||
insize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
memcpy (pBuffer, indata, insize);
|
||||
*pBytesRead = insize;
|
||||
gst_bytestream_flush_fast (bs, insize);
|
||||
|
||||
if (*pBytesRead == nBytesToRead)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
int sinkpad_CIO::Write (const void*, unsigned int, unsigned int*)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sinkpad_CIO::Seek (int nDistance, unsigned int nMoveMode)
|
||||
{
|
||||
GstSeekType seek_type;
|
||||
|
||||
switch (nMoveMode)
|
||||
{
|
||||
case FILE_BEGIN :
|
||||
seek_type = GST_SEEK_METHOD_SET;
|
||||
break;
|
||||
case FILE_CURRENT :
|
||||
seek_type = GST_SEEK_METHOD_CUR;
|
||||
break;
|
||||
case FILE_END :
|
||||
seek_type = GST_SEEK_METHOD_END;
|
||||
break;
|
||||
default :
|
||||
g_print ("wrong seek type\n");
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (gst_bytestream_seek (bs, nDistance, seek_type))
|
||||
return 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int sinkpad_CIO::Create (const char * pName)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sinkpad_CIO::Delete ()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
srcpad_CIO::srcpad_CIO (void)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int srcpad_CIO::Open (const char * pName)
|
||||
{
|
||||
position = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int srcpad_CIO::GetName (char * pBuffer)
|
||||
{
|
||||
strcpy (pBuffer, "");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int srcpad_CIO::GetSize ()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int srcpad_CIO::GetPosition ()
|
||||
{
|
||||
return position;
|
||||
}
|
||||
|
||||
int srcpad_CIO::SetEOF()
|
||||
{
|
||||
GstEvent *event;
|
||||
|
||||
event = gst_event_new (GST_EVENT_EOS);
|
||||
gst_pad_push (srcpad, GST_BUFFER (event));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int srcpad_CIO::Close ()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int srcpad_CIO::Read (void * pBuffer, unsigned int nBytesToRead, unsigned int * pBytesRead)
|
||||
{
|
||||
|
||||
memcpy (pBuffer, header, nBytesToRead);
|
||||
*pBytesRead = nBytesToRead;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int srcpad_CIO::Write (const void * data, unsigned int nBytesToWrite, unsigned int * pBytesWritten)
|
||||
{
|
||||
GstBuffer *buffer;
|
||||
|
||||
/* Save the header for future use */
|
||||
if (position == 0)
|
||||
header = (APE_HEADER *) g_memdup (data, nBytesToWrite);
|
||||
|
||||
buffer = gst_buffer_new ();
|
||||
GST_BUFFER_DATA (buffer) = (guint8 *) g_memdup (data, nBytesToWrite);
|
||||
GST_BUFFER_SIZE (buffer) = nBytesToWrite;
|
||||
position += nBytesToWrite;
|
||||
|
||||
*pBytesWritten = nBytesToWrite;
|
||||
|
||||
gst_pad_push (srcpad, buffer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int srcpad_CIO::Seek (int nDistance, unsigned int nMoveMode)
|
||||
{
|
||||
GstEvent *event;
|
||||
|
||||
switch (nMoveMode)
|
||||
{
|
||||
case FILE_BEGIN :
|
||||
event = gst_event_new_seek ((GstSeekType)(int)(GST_FORMAT_BYTES | GST_SEEK_METHOD_SET), nDistance);
|
||||
position = nDistance;
|
||||
break;
|
||||
case FILE_CURRENT :
|
||||
event = gst_event_new_seek ((GstSeekType)(int)(GST_FORMAT_BYTES | GST_SEEK_METHOD_CUR), nDistance);
|
||||
position += nDistance;
|
||||
break;
|
||||
case FILE_END :
|
||||
event = gst_event_new_seek ((GstSeekType)(int)(GST_FORMAT_BYTES | GST_SEEK_METHOD_END), nDistance);
|
||||
break;
|
||||
default :
|
||||
event = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
if (event)
|
||||
gst_pad_push (srcpad, GST_BUFFER (event));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int srcpad_CIO::Create(const char * pName)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int srcpad_CIO::Delete()
|
||||
{
|
||||
return 0;
|
||||
}
|
77
gst/monkeyaudio/monkey_io.h
Normal file
77
gst/monkeyaudio/monkey_io.h
Normal file
|
@ -0,0 +1,77 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library 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.
|
||||
*/
|
||||
|
||||
#ifndef __MONKEY_IO_H__
|
||||
#define __MONKEY_IO_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/bytestream/bytestream.h>
|
||||
|
||||
#include "libmonkeyaudio/All.h"
|
||||
#include "libmonkeyaudio/GlobalFunctions.h"
|
||||
#include "libmonkeyaudio/MACLib.h"
|
||||
#include "libmonkeyaudio/IO.h"
|
||||
|
||||
class sinkpad_CIO : public CIO
|
||||
{
|
||||
public :
|
||||
GstByteStream *bs;
|
||||
guint64 position;
|
||||
GstPad *sinkpad;
|
||||
|
||||
gboolean eos;
|
||||
gboolean need_discont;
|
||||
|
||||
sinkpad_CIO();
|
||||
int Open(const char * pName);
|
||||
int Close();
|
||||
int Read(void * pBuffer, unsigned int nBytesToRead, unsigned int * pBytesRead);
|
||||
int Write(const void*, unsigned int, unsigned int*);
|
||||
int Seek(int nDistance, unsigned int nMoveMode);
|
||||
int Create(const char * pName);
|
||||
int Delete();
|
||||
int SetEOF();
|
||||
int GetPosition();
|
||||
int GetSize();
|
||||
int GetName(char * pBuffer);
|
||||
};
|
||||
|
||||
|
||||
class srcpad_CIO : public CIO
|
||||
{
|
||||
public :
|
||||
GstPad *srcpad;
|
||||
guint64 position;
|
||||
APE_HEADER *header;
|
||||
|
||||
srcpad_CIO();
|
||||
int Open(const char * pName);
|
||||
int Close();
|
||||
int Read(void * pBuffer, unsigned int nBytesToRead, unsigned int * pBytesRead);
|
||||
int Write(const void*, unsigned int, unsigned int*);
|
||||
int Seek(int nDistance, unsigned int nMoveMode);
|
||||
int Create(const char * pName);
|
||||
int Delete();
|
||||
int SetEOF();
|
||||
int GetPosition();
|
||||
int GetSize();
|
||||
int GetName(char * pBuffer);
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in a new issue