From 520274219a0745384cb9bc6df4d7ee7905090f5d Mon Sep 17 00:00:00 2001 From: Dave Chapman Date: Tue, 5 Jun 2007 16:58:29 +0000 Subject: Initial commit of Monkey's Audio (.ape/.mac) support. Note that Monkey's is an extremely CPU-intensive codec, and that the decoding speed is directly related to the compression level (-c1000, -c2000, -c3000, -c4000 or -c5000) used when encoding the file. Current performance is: -c1000 to -c3000 are realtime on a Gigabeat, -c1000 is realtime on Coldfire targets (H100, H300 and Cowon), and nothing is realtime on PortalPlayer targets (iPods, H10, Sansa). Hopefully this can be improved. More information at FS #7256. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@13562 a1c6a512-1295-4272-9138-f99709370657 --- apps/codecs/Makefile | 16 +- apps/codecs/SOURCES | 1 + apps/codecs/ape.c | 162 +++++++++++++ apps/codecs/demac/COPYING | 339 ++++++++++++++++++++++++++ apps/codecs/demac/Makefile | 43 ++++ apps/codecs/demac/README | 69 ++++++ apps/codecs/demac/demac.c | 272 +++++++++++++++++++++ apps/codecs/demac/libdemac/Makefile | 43 ++++ apps/codecs/demac/libdemac/SOURCES | 10 + apps/codecs/demac/libdemac/crc.c | 119 ++++++++++ apps/codecs/demac/libdemac/decoder.c | 184 ++++++++++++++ apps/codecs/demac/libdemac/decoder.h | 40 ++++ apps/codecs/demac/libdemac/demac.h | 45 ++++ apps/codecs/demac/libdemac/entropy.c | 314 ++++++++++++++++++++++++ apps/codecs/demac/libdemac/entropy.h | 40 ++++ apps/codecs/demac/libdemac/filter.c | 215 +++++++++++++++++ apps/codecs/demac/libdemac/filter.h | 48 ++++ apps/codecs/demac/libdemac/filter_1280_15.c | 27 +++ apps/codecs/demac/libdemac/filter_16_11.c | 27 +++ apps/codecs/demac/libdemac/filter_256_13.c | 27 +++ apps/codecs/demac/libdemac/filter_32_10.c | 27 +++ apps/codecs/demac/libdemac/filter_64_11.c | 27 +++ apps/codecs/demac/libdemac/parser.c | 357 ++++++++++++++++++++++++++++ apps/codecs/demac/libdemac/parser.h | 137 +++++++++++ apps/codecs/demac/libdemac/predictor.c | 196 +++++++++++++++ apps/codecs/demac/libdemac/predictor.h | 36 +++ apps/codecs/demac/libdemac/rangecoding.h | 180 ++++++++++++++ apps/codecs/demac/libdemac/vector_math16.h | 140 +++++++++++ apps/codecs/demac/libdemac/vector_math32.h | 54 +++++ apps/codecs/demac/wavwrite.c | 107 +++++++++ apps/codecs/demac/wavwrite.h | 32 +++ apps/filetypes.c | 2 + apps/metadata.c | 58 +++++ firmware/export/id3.h | 1 + firmware/id3.c | 3 + tools/configure | 38 +-- 36 files changed, 3413 insertions(+), 23 deletions(-) create mode 100644 apps/codecs/ape.c create mode 100644 apps/codecs/demac/COPYING create mode 100644 apps/codecs/demac/Makefile create mode 100644 apps/codecs/demac/README create mode 100644 apps/codecs/demac/demac.c create mode 100644 apps/codecs/demac/libdemac/Makefile create mode 100644 apps/codecs/demac/libdemac/SOURCES create mode 100644 apps/codecs/demac/libdemac/crc.c create mode 100644 apps/codecs/demac/libdemac/decoder.c create mode 100644 apps/codecs/demac/libdemac/decoder.h create mode 100644 apps/codecs/demac/libdemac/demac.h create mode 100644 apps/codecs/demac/libdemac/entropy.c create mode 100644 apps/codecs/demac/libdemac/entropy.h create mode 100644 apps/codecs/demac/libdemac/filter.c create mode 100644 apps/codecs/demac/libdemac/filter.h create mode 100644 apps/codecs/demac/libdemac/filter_1280_15.c create mode 100644 apps/codecs/demac/libdemac/filter_16_11.c create mode 100644 apps/codecs/demac/libdemac/filter_256_13.c create mode 100644 apps/codecs/demac/libdemac/filter_32_10.c create mode 100644 apps/codecs/demac/libdemac/filter_64_11.c create mode 100644 apps/codecs/demac/libdemac/parser.c create mode 100644 apps/codecs/demac/libdemac/parser.h create mode 100644 apps/codecs/demac/libdemac/predictor.c create mode 100644 apps/codecs/demac/libdemac/predictor.h create mode 100644 apps/codecs/demac/libdemac/rangecoding.h create mode 100644 apps/codecs/demac/libdemac/vector_math16.h create mode 100644 apps/codecs/demac/libdemac/vector_math32.h create mode 100644 apps/codecs/demac/wavwrite.c create mode 100644 apps/codecs/demac/wavwrite.h diff --git a/apps/codecs/Makefile b/apps/codecs/Makefile index cece4ad3d0..ba54333104 100644 --- a/apps/codecs/Makefile +++ b/apps/codecs/Makefile @@ -17,7 +17,7 @@ ifdef APPEXTRA endif ifdef SOFTWARECODECS - CODECLIBS = -lmad -la52 -lffmpegFLAC -lTremor -lwavpack -lmusepack -lalac -lfaad -lm4a -lspeex + CODECLIBS = -lmad -la52 -lffmpegFLAC -lTremor -lwavpack -lmusepack -lalac -lfaad -lm4a -lspeex -ldemac endif # we "borrow" the plugin LDS file @@ -39,7 +39,7 @@ DIRS = . CODECDEPS = $(LINKCODEC) $(BUILDDIR)/libcodec.a -.PHONY: libmad liba52 libffmpegFLAC libTremor libspeex libwavpack libmusepack libalac libfaad libm4a +.PHONY: libmad liba52 libffmpegFLAC libTremor libspeex libwavpack libmusepack libalac libfaad libm4a libdemac OUTPUT = $(SOFTWARECODECS) @@ -64,6 +64,7 @@ $(OBJDIR)/wavpack.elf : $(OBJDIR)/wavpack.o $(BUILDDIR)/libwavpack.a $(OBJDIR)/c $(OBJDIR)/alac.elf : $(OBJDIR)/alac.o $(BUILDDIR)/libalac.a $(BUILDDIR)/libm4a.a $(OBJDIR)/codec_crt0.o $(OBJDIR)/aac.elf : $(OBJDIR)/aac.o $(BUILDDIR)/libfaad.a $(BUILDDIR)/libm4a.a $(OBJDIR)/codec_crt0.o $(OBJDIR)/shorten.elf : $(OBJDIR)/shorten.o $(BUILDDIR)/libffmpegFLAC.a $(OBJDIR)/codec_crt0.o +$(OBJDIR)/ape.elf : $(OBJDIR)/ape.o $(BUILDDIR)/libdemac.a $(OBJDIR)/codec_crt0.o $(OBJDIR)/aiff_enc.elf: $(OBJDIR)/aiff_enc.o $(OBJDIR)/codec_crt0.o $(OBJDIR)/mp3_enc.elf: $(OBJDIR)/mp3_enc.o $(OBJDIR)/codec_crt0.o $(OBJDIR)/wav_enc.elf: $(OBJDIR)/wav_enc.o $(OBJDIR)/codec_crt0.o @@ -198,18 +199,25 @@ libfaad: $(SILENT)mkdir -p $(OBJDIR)/libfaad $(call PRINTS,MAKE in libfaad)$(MAKE) -C libfaad OBJDIR=$(OBJDIR)/libfaad OUTPUT=$(BUILDDIR)/libfaad.a +$(BUILDDIR)/libdemac.a: libdemac + +libdemac: + $(SILENT)mkdir -p $(OBJDIR)/libdemac + $(call PRINTS,MAKE in libdemac)$(MAKE) -C demac/libdemac OBJDIR=$(OBJDIR)/libdemac OUTPUT=$(BUILDDIR)/libdemac.a + clean: - $(call PRINTS,cleaning codecs)rm -fr $(OBJDIR)/libmad $(BUILDDIR)/libmad.a $(OBJDIR)/liba52 $(BUILDDIR)/liba52.a $(OBJDIR)/libffmpegFLAC $(BUILDDIR)/libffmpegFLAC.a $(OBJDIR)/Tremor $(BUILDDIR)/libTremor.a $(OBJDIR)/libspeex $(BUILDDIR)/libSpeex.a $(OBJDIR)/libwavpack $(BUILDDIR)/libwavpack.a $(OBJDIR)/libmusepack $(BUILDDIR)/libmusepack.a $(OBJDIR)/libalac $(BUILDDIR)/libalac.a $(OBJDIR)/libfaad $(BUILDDIR)/libfaad.a $(OBJDIR)/libm4a $(BUILDDIR)/libm4a.a + $(call PRINTS,cleaning codecs)rm -fr $(OBJDIR)/libmad $(BUILDDIR)/libmad.a $(OBJDIR)/liba52 $(BUILDDIR)/liba52.a $(OBJDIR)/libffmpegFLAC $(BUILDDIR)/libffmpegFLAC.a $(OBJDIR)/Tremor $(BUILDDIR)/libTremor.a $(OBJDIR)/libspeex $(BUILDDIR)/libSpeex.a $(OBJDIR)/libwavpack $(BUILDDIR)/libwavpack.a $(OBJDIR)/libmusepack $(BUILDDIR)/libmusepack.a $(OBJDIR)/libalac $(BUILDDIR)/libalac.a $(OBJDIR)/libfaad $(BUILDDIR)/libfaad.a $(OBJDIR)/libm4a $(BUILDDIR)/libm4a.a $(OBJDIR)/libdemac $(BUILDDIR)/libdemac.a $(SILENT)$(MAKE) -C libmad clean OBJDIR=$(OBJDIR)/libmad $(SILENT)$(MAKE) -C liba52 clean OBJDIR=$(OBJDIR)/liba52 $(SILENT)$(MAKE) -C libffmpegFLAC clean OBJDIR=$(OBJDIR)/libffmpegFLAC $(SILENT)$(MAKE) -C Tremor clean OBJDIR=$(OBJDIR)/Tremor - $(SILENT)$(MAKE) -C libspeex clean OBJDIR=$(OBJDIR)/libspeex + $(SILENT)$(MAKE) -C libspeex clean OBJDIR=$(OBJDIR)/libspeex $(SILENT)$(MAKE) -C libwavpack clean OBJDIR=$(OBJDIR)/libwavpack $(SILENT)$(MAKE) -C libmusepack clean OBJDIR=$(OBJDIR)/libmusepack $(SILENT)$(MAKE) -C libalac clean OBJDIR=$(OBJDIR)/libalac $(SILENT)$(MAKE) -C libfaad clean OBJDIR=$(OBJDIR)/libfaad $(SILENT)$(MAKE) -C libm4a clean OBJDIR=$(OBJDIR)/libm4a + $(SILENT)$(MAKE) -C demac/libdemac clean OBJDIR=$(OBJDIR)/libdemac $(SILENT)$(MAKE) -C lib clean OBJDIR=$(OBJDIR)/lib ifneq ($(MAKECMDGOALS),clean) diff --git a/apps/codecs/SOURCES b/apps/codecs/SOURCES index 123a9c0f3f..7a3d4055cc 100644 --- a/apps/codecs/SOURCES +++ b/apps/codecs/SOURCES @@ -11,6 +11,7 @@ alac.c #if MEMORYSIZE > 1 aac.c #endif +ape.c shorten.c aiff.c speex.c diff --git a/apps/codecs/ape.c b/apps/codecs/ape.c new file mode 100644 index 0000000000..b77abc0c74 --- /dev/null +++ b/apps/codecs/ape.c @@ -0,0 +1,162 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2007 Dave Chapman + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include "codeclib.h" +#define ROCKBOX +#include + +CODEC_HEADER + +#define BLOCKS_PER_LOOP 4608 +#define MAX_CHANNELS 2 +#define MAX_BYTESPERSAMPLE 3 + +#define INPUT_CHUNKSIZE (32*1024) + +/* 4608*4 = 18432 bytes per channel */ +static int32_t decoded0[BLOCKS_PER_LOOP] IBSS_ATTR; +static int32_t decoded1[BLOCKS_PER_LOOP] IBSS_ATTR; + +#define MAX_SUPPORTED_SEEKTABLE_SIZE 5000 + +/* this is the codec entry point */ +enum codec_status codec_main(void) +{ + struct ape_ctx_t ape_ctx; + uint32_t samplesdone; + uint32_t elapsedtime; + size_t bytesleft; + int retval; + + uint32_t currentframe; + int nblocks; + int bytesconsumed; + unsigned char* inbuffer; + int blockstodecode; + int res; + int firstbyte; + + /* Generic codec initialisation */ + ci->configure(CODEC_SET_FILEBUF_WATERMARK, 1024*512); + ci->configure(CODEC_SET_FILEBUF_CHUNKSIZE, 1024*128); + + ci->configure(DSP_SET_SAMPLE_DEPTH, APE_OUTPUT_DEPTH-1); + + next_track: + + if (codec_init()) { + LOGF("APE: Error initialising codec\n"); + retval = CODEC_ERROR; + goto exit; + } + + inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE); + + /* Read the file headers to populate the ape_ctx struct */ + if (ape_parseheaderbuf(inbuffer,&ape_ctx) < 0) { + LOGF("APE: Error reading header\n"); + retval = CODEC_ERROR; + goto exit; + } + ci->advance_buffer(ape_ctx.firstframe); + + while (!*ci->taginfo_ready && !ci->stop_codec) + ci->sleep(1); + + ci->configure(DSP_SWITCH_FREQUENCY, ape_ctx.samplerate); + ci->configure(DSP_SET_STEREO_MODE, ape_ctx.channels == 1 ? + STEREO_MONO : STEREO_NONINTERLEAVED); + codec_set_replaygain(ci->id3); + + /* The main decoding loop */ + + currentframe = 0; + samplesdone = 0; + + /* Initialise the buffer */ + inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE); + firstbyte = 3; /* Take account of the little-endian 32-bit byte ordering */ + + /* The main decoding loop - we decode the frames a small chunk at a time */ + while (currentframe < ape_ctx.totalframes) + { + /* Calculate how many blocks there are in this frame */ + if (currentframe == (ape_ctx.totalframes - 1)) + nblocks = ape_ctx.finalframeblocks; + else + nblocks = ape_ctx.blocksperframe; + + ape_ctx.currentframeblocks = nblocks; + + /* Initialise the frame decoder */ + init_frame_decoder(&ape_ctx, inbuffer, &firstbyte, &bytesconsumed); + + ci->advance_buffer(bytesconsumed); + inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE); + + /* Decode the frame a chunk at a time */ + while (nblocks > 0) + { + ci->yield(); + if (ci->stop_codec || ci->new_track) { + break; + } + + blockstodecode = MIN(BLOCKS_PER_LOOP, nblocks); + + if ((res = decode_chunk(&ape_ctx, inbuffer, &firstbyte, + &bytesconsumed, + decoded0, decoded1, + blockstodecode)) < 0) + { + /* Frame decoding error, abort */ + LOGF("APE: Frame %d, error %d\n",currentframe,res); + retval = CODEC_ERROR; + goto done; + } + + ci->yield(); + ci->pcmbuf_insert(decoded0, decoded1, blockstodecode); + + /* Update the elapsed-time indicator */ + samplesdone += blockstodecode; + elapsedtime = (samplesdone*10)/(ape_ctx.samplerate/100); + ci->set_elapsed(elapsedtime); + + ci->advance_buffer(bytesconsumed); + inbuffer = ci->request_buffer(&bytesleft, INPUT_CHUNKSIZE); + + /* Decrement the block count */ + nblocks -= blockstodecode; + } + + currentframe++; + } + + retval = CODEC_OK; + +done: + LOGF("APE: Decoded %ld samples\n",samplesdone); + + if (ci->request_next_track()) + goto next_track; + +exit: + return retval; +} diff --git a/apps/codecs/demac/COPYING b/apps/codecs/demac/COPYING new file mode 100644 index 0000000000..d511905c16 --- /dev/null +++ b/apps/codecs/demac/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/apps/codecs/demac/Makefile b/apps/codecs/demac/Makefile new file mode 100644 index 0000000000..e0ed4ad341 --- /dev/null +++ b/apps/codecs/demac/Makefile @@ -0,0 +1,43 @@ +# $Id:$ + +FILTERS = libdemac/filter_16_11.o libdemac/filter_64_11.o libdemac/filter_256_13.o libdemac/filter_32_10.o libdemac/filter_1280_15.o +LIBOBJS = libdemac/parser.o libdemac/decoder.o libdemac/entropy.o libdemac/predictor.o libdemac/crc.o $(FILTERS) +OBJS = demac.o wavwrite.o $(LIBOBJS) + +CFLAGS = -Wall -O3 -Ilibdemac + +ifeq ($(findstring CYGWIN,$(shell uname)),CYGWIN) +EXT = .exe +CROSS = +CFLAGS += -mno-cygwin +else + ifdef WIN + EXT = .exe + CROSS = i586-mingw32msvc- + else + EXT = + CROSS = + endif +endif + +CC = $(CROSS)gcc +STRIP = $(CROSS)strip +OUTPUT = demac$(EXT) + +all: $(OUTPUT) + +$(OUTPUT): $(OBJS) + $(CC) -o $(OUTPUT) $(OBJS) + +.c.o : + $(CC) $(CFLAGS) $(INC) -c -o $@ $< + +libdemac/filter_16_11.o: libdemac/filter.c +libdemac/filter_64_11.o: libdemac/filter.c +libdemac/filter_256_13.o: libdemac/filter.c +libdemac/filter_1280_15.o: libdemac/filter.c +libdemac/filter_32_10.o: libdemac/filter.c +libdemac/entropy.o: libdemac/rangecoding.h + +clean: + rm -f $(OUTPUT) $(OBJS) *~ */*~ diff --git a/apps/codecs/demac/README b/apps/codecs/demac/README new file mode 100644 index 0000000000..2fcdd95edf --- /dev/null +++ b/apps/codecs/demac/README @@ -0,0 +1,69 @@ +demac - a decoder for Monkey's Audio files. + +Introduction + +demac is an implementation in portable ANSI C of a decoder for the +Monkey's Audio lossless compression format. It has the following +features: + + * Open source (GNU GPL) + * Written in portable ANSI C + * Designed for use on low memory and embedded devices. All internal + buffers are statically declared - the core library doesn't require + malloc/free. This has the disadvantage that the library isn't + re-entrant. + + +Compatibility + + +libdemac is still in the early stages of development but has been +relatively well tested with v3.99 files at all compression levels. + +v3.97 files have received less testing - 16-bit files seem to work, +but 24-bit files are causing problems in the range decoder. + +Files earlier than v3.97 are not supported by libdemac, but support +might be added in the future. + + +Source Code + +The source code in this directory is structured as follows: + +demac/Makefile - Makefile for the standalone demac decoder +demac/demac.c - Simple standalone test program to decoder an APE file to WAV +demac/wavwrite.[ch] - Helper functions for demac.c +demac/libdemac/Makefile - A Makefile for use in Rockbox +demac/libdemac/*.[ch] - The main libdemac code + + +Latest Version + +The latest version of demac and libdemac can always be found in the +"apps/codecs/demac/" directory in the Rockbox source. You can check +this out from svn with the command: + +svn co svn://svn.rockbox.org/rockbox/trunk/apps/codecs/demac demac + +Or browse the source code online here: + +http://svn.rockbox.org/viewvc.cgi/trunk/apps/codecs/demac + + + +Acknowledgements + +Thanks to Matt. T. Ashland for writing Monkey's Audio. His website +can be found here: http://www.monkeysaudio.com + + +Copyright and license + + +libdemac is (C) 2007 Dave Chapman and is licensed under the GNU +GPL. See the COPYING file in this directory. + +The exception is the majority of rangecoding.h, which is (C) 1997, +1998, 1999, 2000 Michael Schindler and is also licensed under the GPL. +See that source file for full details. diff --git a/apps/codecs/demac/demac.c b/apps/codecs/demac/demac.c new file mode 100644 index 0000000000..da132ff248 --- /dev/null +++ b/apps/codecs/demac/demac.c @@ -0,0 +1,272 @@ +/* + +demac - A Monkey's Audio decoder + +$Id:$ + +Copyright (C) Dave Chapman 2007 + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA + +*/ + +/* + +This example is intended to demonstrate how the decoder can be used in +embedded devices - there is no usage of dynamic memory (i.e. no +malloc/free) and small buffer sizes are chosen to minimise both the +memory usage and decoding latency. + +This implementation requires the following memory and supports decoding of all APE files up to 24-bit Stereo. + +32768 - data from the input stream to be presented to the decoder in one contiguous chunk. +18432 - decoding buffer (left channel) +18432 - decoding buffer (right channel) + +17408+5120+2240 - buffers used for filter histories (compression levels 2000-5000) + +In addition, this example uses a static 27648 byte buffer as temporary +storage for outputting the data to a WAV file but that could be +avoided by writing the decoded data one sample at a time. + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "demac.h" +#include "wavwrite.h" + +#ifndef __WIN32__ +#define O_BINARY 0 +#endif + +#define CALC_CRC 1 + +#define BLOCKS_PER_LOOP 4608 +#define MAX_CHANNELS 2 +#define MAX_BYTESPERSAMPLE 3 + +#define INPUT_CHUNKSIZE (32*1024) + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + + +/* 4608*2*3 = 27648 bytes */ +static unsigned char wavbuffer[BLOCKS_PER_LOOP*MAX_CHANNELS*MAX_BYTESPERSAMPLE]; + +/* 4608*4 = 18432 bytes per channel */ +static int32_t decoded0[BLOCKS_PER_LOOP]; +static int32_t decoded1[BLOCKS_PER_LOOP]; + +/* We assume that 32KB of compressed data is enough to extract up to + 27648 bytes of decompressed data. */ + +static unsigned char inbuffer[INPUT_CHUNKSIZE]; + +int ape_decode(char* infile, char* outfile) +{ + int fd; + int fdwav; + int currentframe; + int nblocks; + int bytesconsumed; + struct ape_ctx_t ape_ctx; + int i, n; + unsigned char* p; + int bytesinbuffer; + int blockstodecode; + int res; + int firstbyte; + int16_t sample16; + int32_t sample32; + uint32_t frame_crc; + int crc_errors = 0; + + fd = open(infile,O_RDONLY|O_BINARY); + if (fd < 0) return -1; + + /* Read the file headers to populate the ape_ctx struct */ + if (ape_parseheader(fd,&ape_ctx) < 0) { + printf("Cannot read header\n"); + close(fd); + return -1; + } + + if ((ape_ctx.fileversion < APE_MIN_VERSION) || (ape_ctx.fileversion > APE_MAX_VERSION)) { + printf("Unsupported file version - %.2f\n", ape_ctx.fileversion/1000.0); + close(fd); + return -2; + } + + //ape_dumpinfo(&ape_ctx); + + printf("Decoding file - v%.2f, compression level %d\n",ape_ctx.fileversion/1000.0,ape_ctx.compressiontype); + + /* Open the WAV file and write a canonical 44-byte WAV header + based on the audio format information in the ape_ctx struct. + + NOTE: This example doesn't write the original WAV header and + tail data which are (optionally) stored in the APE file. + */ + fdwav = open_wav(&ape_ctx,outfile); + + currentframe = 0; + + /* Initialise the buffer */ + lseek(fd, ape_ctx.firstframe, SEEK_SET); + bytesinbuffer = read(fd, inbuffer, INPUT_CHUNKSIZE); + firstbyte = 3; /* Take account of the little-endian 32-bit byte ordering */ + + /* The main decoding loop - we decode the frames a small chunk at a time */ + while (currentframe < ape_ctx.totalframes) + { + /* Calculate how many blocks there are in this frame */ + if (currentframe == (ape_ctx.totalframes - 1)) + nblocks = ape_ctx.finalframeblocks; + else + nblocks = ape_ctx.blocksperframe; + + ape_ctx.currentframeblocks = nblocks; + + /* Initialise the frame decoder */ + init_frame_decoder(&ape_ctx, inbuffer, &firstbyte, &bytesconsumed); + + /* Update buffer */ + memmove(inbuffer,inbuffer + bytesconsumed, bytesinbuffer - bytesconsumed); + bytesinbuffer -= bytesconsumed; + + n = read(fd, inbuffer + bytesinbuffer, INPUT_CHUNKSIZE - bytesinbuffer); + bytesinbuffer += n; + +#if CALC_CRC + frame_crc = ape_initcrc(); +#endif + + /* Decode the frame a chunk at a time */ + while (nblocks > 0) + { + blockstodecode = MIN(BLOCKS_PER_LOOP, nblocks); + + if ((res = decode_chunk(&ape_ctx, inbuffer, &firstbyte, + &bytesconsumed, + decoded0, decoded1, + blockstodecode)) < 0) + { + /* Frame decoding error, abort */ + close(fd); + return res; + } + + /* Convert the output samples to WAV format and write to output file */ + p = wavbuffer; + if (ape_ctx.bps == 16) { + for (i = 0 ; i < blockstodecode ; i++) + { + sample16 = decoded0[i]; + *(p++) = sample16 & 0xff; + *(p++) = (sample16&0xff00) >> 8; + + if (ape_ctx.channels == 2) { + sample16 = decoded1[i]; + *(p++) = sample16 & 0xff; + *(p++) = (sample16&0xff00) >> 8; + } + } + } else if (ape_ctx.bps == 24) { + for (i = 0 ; i < blockstodecode ; i++) + { + sample32 = decoded0[i]; + *(p++) = sample32 & 0xff; + *(p++) = (sample32&0xff00) >> 8; + *(p++) = (sample32&0xff0000) >> 16; + + if (ape_ctx.channels == 2) { + sample32 = decoded1[i]; + *(p++) = sample32 & 0xff; + *(p++) = (sample32&0xff00) >> 8; + *(p++) = (sample32&0xff0000) >> 16; + } + } + } + +#if CALC_CRC + frame_crc = ape_updatecrc(wavbuffer, p - wavbuffer, frame_crc); +#endif + write(fdwav,wavbuffer,p - wavbuffer); + + /* Update the buffer */ + memmove(inbuffer,inbuffer + bytesconsumed, bytesinbuffer - bytesconsumed); + bytesinbuffer -= bytesconsumed; + + n = read(fd, inbuffer + bytesinbuffer, INPUT_CHUNKSIZE - bytesinbuffer); + bytesinbuffer += n; + + /* Decrement the block count */ + nblocks -= blockstodecode; + } + +#if CALC_CRC + frame_crc = ape_finishcrc(frame_crc); + + if (ape_ctx.CRC != frame_crc) + { + fprintf(stderr,"CRC error in frame %d\n",currentframe); + crc_errors++; + } +#endif + + currentframe++; + } + + close(fd); + close(fdwav); + + if (crc_errors > 0) + return -1; + else + return 0; +} + +int main(int argc, char* argv[]) +{ + int res; + + if (argc != 3) { + fprintf(stderr,"Usage: demac infile.ape outfile.wav\n"); + return 0; + } + + res = ape_decode(argv[1], argv[2]); + + if (res < 0) + { + fprintf(stderr,"DECODING ERROR %d, ABORTING\n", res); + } + else + { + fprintf(stderr,"DECODED OK - NO CRC ERRORS.\n"); + } + + return 0; +} diff --git a/apps/codecs/demac/libdemac/Makefile b/apps/codecs/demac/libdemac/Makefile new file mode 100644 index 0000000000..7fc784dd5f --- /dev/null +++ b/apps/codecs/demac/libdemac/Makefile @@ -0,0 +1,43 @@ +# __________ __ ___. +# Open \______ \ ____ ____ | | _\_ |__ _______ ___ +# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / +# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < +# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ +# \/ \/ \/ \/ \/ +# $Id:$ +# + +INCLUDES=-I$(APPSDIR) -I.. -I. -I$(FIRMDIR)/include -I$(FIRMDIR)/export \ + -I$(FIRMDIR)/common -I$(FIRMDIR)/drivers -I$(BUILDDIR) + +ifdef APPEXTRA + INCLUDES += $(patsubst %,-I$(APPSDIR)/%,$(subst :, ,$(APPEXTRA))) +endif + +DEMACOPTS = -O3 -DROCKBOX +CFLAGS = $(INCLUDES) $(GCCOPTS) $(TARGET_INC) $(DEMACOPTS) $(TARGET) \ +$(EXTRA_DEFINES) -DMEM=${MEMORYSIZE} $(PROFILE_OPTS) + +# This sets up 'SRC' based on the files mentioned in SOURCES +include $(TOOLSDIR)/makesrc.inc + +SOURCES = $(SRC) +OBJS2 := $(SRC:%.c=$(OBJDIR)/%.o) +OBJS = $(patsubst %.S, $(OBJDIR)/%.o, $(OBJS2)) +DEPFILE = $(OBJDIR)/dep-libdemac +DIRS = + +all: $(OUTPUT) + +$(OUTPUT): $(OBJS) + $(call PRINTS,AR+RANLIB $(@F))$(AR) ruv $@ $+ >/dev/null 2>&1 + $(SILENT)$(RANLIB) $@ + +include $(TOOLSDIR)/make.inc + +clean: + $(call PRINTS,cleaning libdemac)rm -f $(OBJS) $(OUTPUT) $(DEPFILE) + +ifneq ($(MAKECMDGOALS),clean) +-include $(DEPFILE) +endif diff --git a/apps/codecs/demac/libdemac/SOURCES b/apps/codecs/demac/libdemac/SOURCES new file mode 100644 index 0000000000..76b891a90d --- /dev/null +++ b/apps/codecs/demac/libdemac/SOURCES @@ -0,0 +1,10 @@ +crc.c +predictor.c +entropy.c +decoder.c +parser.c +filter_1280_15.c +filter_16_11.c +filter_256_13.c +filter_32_10.c +filter_64_11.c diff --git a/apps/codecs/demac/libdemac/crc.c b/apps/codecs/demac/libdemac/crc.c new file mode 100644 index 0000000000..c23de7d043 --- /dev/null +++ b/apps/codecs/demac/libdemac/crc.c @@ -0,0 +1,119 @@ +/* + +libdemac - A Monkey's Audio decoder + +$Id:$ + +Copyright (C) Dave Chapman 2007 + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA + +*/ + +#include + +static uint32_t crctab32[] = +{ + 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, + 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, + 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, + 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, + 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, + 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, + 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, + 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, + 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, + 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, + 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, + 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, + 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, + 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, + 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, + 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, + + 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, + 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, + 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, + 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, + 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, + 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, + 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, + 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, + 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, + 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, + 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, + 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, + 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, + 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, + 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, + 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, + + 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, + 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, + 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, + 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, + 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, + 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, + 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, + 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, + 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, + 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, + 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, + 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, + 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, + 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, + 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, + 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, + + 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, + 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, + 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, + 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, + 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, + 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, + 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, + 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, + 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, + 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, + 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, + 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, + 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, + 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, + 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, + 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D +}; + +uint32_t ape_initcrc(void) +{ + return 0xffffffff; +} + +/* Update the CRC from a block of WAV-format audio data */ +uint32_t ape_updatecrc(unsigned char *block, int count, uint32_t crc) +{ + while (count--) + crc = (crc >> 8) ^ crctab32[(crc & 0xff) ^ *block++]; + + return crc; +} + +uint32_t ape_finishcrc(uint32_t crc) +{ + crc ^= 0xffffffff; + crc >>= 1; + + return crc; +} + diff --git a/apps/codecs/demac/libdemac/decoder.c b/apps/codecs/demac/libdemac/decoder.c new file mode 100644 index 0000000000..22b6e8d325 --- /dev/null +++ b/apps/codecs/demac/libdemac/decoder.c @@ -0,0 +1,184 @@ +/* + +libdemac - A Monkey's Audio decoder + +$Id:$ + +Copyright (C) Dave Chapman 2007 + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA + +*/ + +#include +#include + +#include "demac.h" +#include "predictor.h" +#include "entropy.h" +#include "filter.h" + +/* Statically allocate the filter buffers */ + +static int16_t filterbuf32[(32*3 + HISTORY_SIZE) * 2] IBSS_ATTR; /* 4480 bytes */ +static int16_t filterbuf256[(256*3 + HISTORY_SIZE) * 2] IBSS_ATTR; /* 5120 bytes */ + +/* This is only needed for "insane" files, and no Rockbox targets can + hope to decode them in realtime anyway. */ +static int16_t filterbuf1280[(1280*3 + HISTORY_SIZE) * 2]; /* 17408 bytes */ + +void init_frame_decoder(struct ape_ctx_t* ape_ctx, + unsigned char* inbuffer, int* firstbyte, + int* bytesconsumed) +{ + init_entropy_decoder(ape_ctx, inbuffer, firstbyte, bytesconsumed); + //printf("CRC=0x%08x\n",ape_ctx->CRC); + //printf("Flags=0x%08x\n",ape_ctx->frameflags); + + init_predictor_decoder(ape_ctx); + + switch (ape_ctx->compressiontype) + { + case 2000: + init_filter_16_11(filterbuf32); + break; + + case 3000: + init_filter_64_11(filterbuf256); + break; + + case 4000: + init_filter_256_13(filterbuf256); + init_filter_32_10(filterbuf32); + break; + + case 5000: + init_filter_1280_15(filterbuf1280); + init_filter_256_13(filterbuf256); + init_filter_16_11(filterbuf32); + } +} + +int decode_chunk(struct ape_ctx_t* ape_ctx, + unsigned char* inbuffer, int* firstbyte, + int* bytesconsumed, + int32_t* decoded0, int32_t* decoded1, + int count) +{ + int res; + int32_t left, right; +#ifdef ROCKBOX + int scale = (APE_OUTPUT_DEPTH - ape_ctx->bps); + #define SCALE(x) ((x) << scale) +#else + #define SCALE(x) (x) +#endif + + if ((ape_ctx->channels==1) || (ape_ctx->frameflags & APE_FRAMECODE_PSEUDO_STEREO)) { + if (ape_ctx->frameflags & APE_FRAMECODE_STEREO_SILENCE) { + res = entropy_decode(ape_ctx, inbuffer, firstbyte, bytesconsumed, decoded0, decoded1, count); + /* We are pure silence, so we're done. */ + return 0; + } else { + res = entropy_decode(ape_ctx, inbuffer, firstbyte, bytesconsumed, decoded0, NULL, count); + } + + switch (ape_ctx->compressiontype) + { + case 2000: + apply_filter_16_11(ape_ctx->fileversion,decoded0,NULL,count); + break; + + case 3000: + apply_filter_64_11(ape_ctx->fileversion,decoded0,NULL,count); + break; + + case 4000: + apply_filter_32_10(ape_ctx->fileversion,decoded0,NULL,count); + apply_filter_256_13(ape_ctx->fileversion,decoded0,NULL,count); + break; + + case 5000: + apply_filter_16_11(ape_ctx->fileversion,decoded0,NULL,count); + apply_filter_256_13(ape_ctx->fileversion,decoded0,NULL,count); + apply_filter_1280_15(ape_ctx->fileversion,decoded0,NULL,count); + } + + /* Now apply the predictor decoding */ + predictor_decode_mono(ape_ctx,decoded0,count); + + if (ape_ctx->channels==2) { + /* Pseudo-stereo - just copy left channel to right channel */ + while (count--) + { + left = *decoded0; + *(decoded1++) = *(decoded0++) = SCALE(left); + } + } else { + /* Mono - do nothing unless it's 8-bit audio */ + if (ape_ctx->bps == 8) { + /* TODO: Handle 8-bit streams */ + } + } + } else { /* Stereo */ + if (ape_ctx->frameflags & APE_FRAMECODE_STEREO_SILENCE) { + /* We are pure silence, so we're done. */ + return 0; + } + + res = entropy_decode(ape_ctx, inbuffer, firstbyte, bytesconsumed, decoded0, decoded1, count); + + /* Apply filters - compression type 1000 doesn't have any */ + switch (ape_ctx->compressiontype) + { + case 2000: + apply_filter_16_11(ape_ctx->fileversion,decoded0,decoded1,count); + break; + + case 3000: + apply_filter_64_11(ape_ctx->fileversion,decoded0,decoded1,count); + break; + + case 4000: + apply_filter_32_10(ape_ctx->fileversion,decoded0,decoded1,count); + apply_filter_256_13(ape_ctx->fileversion,decoded0,decoded1,count); + break; + + case 5000: + apply_filter_16_11(ape_ctx->fileversion,decoded0,decoded1,count); + apply_filter_256_13(ape_ctx->fileversion,decoded0,decoded1,count); + apply_filter_1280_15(ape_ctx->fileversion,decoded0,decoded1,count); + } + + /* Now apply the predictor decoding */ + predictor_decode_stereo(ape_ctx,decoded0,decoded1,count); + + if (ape_ctx->bps == 8) { + /* TODO: Handle 8-bit streams */ + } else { + /* Decorrelate and scale to output depth */ + while (count--) + { + left = *decoded1 - (*decoded0 / 2); + right = left + *decoded0; + + *(decoded0++) = SCALE(left); + *(decoded1++) = SCALE(right); + } + } + } + + return res; +} diff --git a/apps/codecs/demac/libdemac/decoder.h b/apps/codecs/demac/libdemac/decoder.h new file mode 100644 index 0000000000..0c3bd15b37 --- /dev/null +++ b/apps/codecs/demac/libdemac/decoder.h @@ -0,0 +1,40 @@ +/* + +libdemac - A Monkey's Audio decoder + +$Id:$ + +Copyright (C) Dave Chapman 2007 + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA + +*/ + +#ifndef _APE_DECODER_H +#define _APE_DECODER_H + +#include +#include "parser.h" + +void init_frame_decoder(struct ape_ctx_t* ape_ctx, + unsigned char* inbuffer, int* firstbyte, + int* bytesconsumed); + +int decode_chunk(struct ape_ctx_t* ape_ctx, + unsigned char* inbuffer, int* firstbyte, + int* bytesconsumed, + int32_t* decoded0, int32_t* decoded1, + int count); +#endif diff --git a/apps/codecs/demac/libdemac/demac.h b/apps/codecs/demac/libdemac/demac.h new file mode 100644 index 0000000000..d1bb361574 --- /dev/null +++ b/apps/codecs/demac/libdemac/demac.h @@ -0,0 +1,45 @@ +/* + +libdemac - A Monkey's Audio decoder + +$Id:$ + +Copyright (C) Dave Chapman 2007 + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA + +*/ + +#ifndef _APE_DECODER_H +#define _APE_DECODER_H + +#include +#include "parser.h" + +void init_frame_decoder(struct ape_ctx_t* ape_ctx, + unsigned char* inbuffer, int* firstbyte, + int* bytesconsumed); + +int decode_chunk(struct ape_ctx_t* ape_ctx, + unsigned char* inbuffer, int* firstbyte, + int* bytesconsumed, + int32_t* decoded0, int32_t* decoded1, + int count); + +uint32_t ape_initcrc(void); +uint32_t ape_updatecrc(unsigned char *block, int count, uint32_t crc); +uint32_t ape_finishcrc(uint32_t crc); + +#endif diff --git a/apps/codecs/demac/libdemac/entropy.c b/apps/codecs/demac/libdemac/entropy.c new file mode 100644 index 0000000000..2c60420250 --- /dev/null +++ b/apps/codecs/demac/libdemac/entropy.c @@ -0,0 +1,314 @@ +/* + +libdemac - A Monkey's Audio decoder + +$Id:$ + +Copyright (C) Dave Chapman 2007 + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA + +*/ + +#include +#include + +#include "parser.h" +#include "entropy.h" +#include "rangecoding.h" /* Range-coding (static inline) functions */ + +#define MODEL_ELEMENTS 64 + +/* + The following counts arrays for use with the range decoder are + hard-coded in the Monkey's Audio decoder. +*/ + +static const int counts_3970[65] ICONST_ATTR = +{ + 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 +}; + +/* counts_diff_3970[i] = counts_3970[i+1] - counts_3970[i] */ +static const int counts_diff_3970[64] ICONST_ATTR = +{ + 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 +}; + +static const int counts_3980[65] ICONST_ATTR = +{ + 0,19578,36160,48417,56323,60899,63265,64435, + 64971,65232,65351,65416,65447,65466,65476,65482, + 65485,65488,65490,65491,65492,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 +}; + +/* counts_diff_3980[i] = counts_3980[i+1] - counts_3980[i] */ + +static const int counts_diff_3980[64] ICONST_ATTR = +{ + 19578,16582,12257,7906,4576,2366,1170,536, + 261,119,65,31,19,10,6,3, + 3,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,1,1,1 +}; + +/* + range_get_symbol_* functions based on main decoding loop in simple_d.c from + http://www.compressconsult.com/rangecoder/rngcod13.zip + (c) Michael Schindler +*/ + +static inline int range_get_symbol_3980(void) +{ + int symbol, cf; + + cf = range_decode_culshift(16); + + /* figure out the symbol inefficiently; a binary search would be much better */ + for (symbol = 0; counts_3980[symbol+1] <= cf; symbol++); + + range_decode_update(counts_diff_3980[symbol],counts_3980[symbol]); + + return symbol; +} + +static inline int range_get_symbol_3970(void) +{ + int symbol, cf; + + cf = range_decode_culshift(16); + + /* figure out the symbol inefficiently; a binary search would be much better */ + for (symbol = 0; counts_3970[symbol+1] <= cf; symbol++); + + range_decode_update(counts_diff_3970[symbol],counts_3970[symbol]); + + return symbol; +} + +/* MAIN DECODING FUNCTIONS */ + +struct rice_t +{ + uint32_t k; + uint32_t ksum; +}; + +static struct rice_t riceX IBSS_ATTR; +static struct rice_t riceY IBSS_ATTR; + +static inline void update_rice(struct rice_t* rice, int x) +{ + rice->ksum += ((x + 1) / 2) - ((rice->ksum + 16) >> 5); + + if (rice->k == 0) { + rice->k = 1; + } else if (rice->ksum < ((uint32_t)1 << (rice->k + 4))) { + rice->k--; + } else if (rice->ksum >= ((uint32_t)1 << (rice->k + 5))) { + rice->k++; + } +} + +static inline int entropy_decode3980(struct rice_t* rice) +{ + int base, x, pivot, overflow; + + pivot = rice->ksum >> 5; + if (pivot == 0) pivot=1; + + overflow = range_get_symbol_3980(); + + if (overflow == (MODEL_ELEMENTS-1)) { + overflow = range_decode_short() << 16; + overflow |= range_decode_short(); + } + + if (pivot >= 0x10000) { + /* Codepath for 24-bit streams */ + int nbits, lo_bits, base_hi, base_lo; + + /* Count the number of bits in pivot */ + nbits = 17; /* We know there must be at least 17 bits */ + while ((pivot >> nbits) > 0) { nbits++; } + + /* base_lo is the low (nbits-16) bits of base + base_hi is the high 16 bits of base + */ + lo_bits = (nbits - 16); + + base_hi = range_decode_culfreq((pivot >> lo_bits) + 1); + range_decode_update(1, base_hi); + + base_lo = range_decode_culfreq(1 << lo_bits); + range_decode_update(1, base_lo); + + base = (base_hi << lo_bits) + base_lo; + } else { + /* Codepath for 16-bit streams */ + base = range_decode_culfreq(pivot); + range_decode_update(1, base); + } + + x = base + (overflow * pivot); + update_rice(rice, x); + + /* Convert to signed */ + if (x & 1) + return (x >> 1) + 1; + else + return -(x >> 1); +} + + +static inline int entropy_decode3970(struct rice_t* rice) +{ + int x, tmpk; + + int overflow = range_get_symbol_3970(); + + if (overflow == (MODEL_ELEMENTS - 1)) { + tmpk = range_decode_bits(5); + overflow = 0; + } else { + tmpk = (rice->k < 1) ? 0 : rice->k - 1; + } + + if (tmpk <= 16) { + x = range_decode_bits(tmpk); + } else { + x = range_decode_short(); + x |= (range_decode_bits(tmpk - 16) << 16); + } + x += (overflow << tmpk); + + update_rice(rice, x); + + /* Convert to signed */ + if (x & 1) + return (x >> 1) + 1; + else + return -(x >> 1); +} + +void init_entropy_decoder(struct ape_ctx_t* ape_ctx, + unsigned char* inbuffer, int* firstbyte, + int* bytesconsumed) +{ + bytebuffer = inbuffer; + bytebufferoffset = *firstbyte; + + /* Read the CRC */ + ape_ctx->CRC = read_byte(); + ape_ctx->CRC = (ape_ctx->CRC << 8) | read_byte(); + ape_ctx->CRC = (ape_ctx->CRC << 8) | read_byte(); + ape_ctx->CRC = (ape_ctx->CRC << 8) | read_byte(); + + /* Read the frame flags if they exist */ + ape_ctx->frameflags = 0; + if ((ape_ctx->fileversion > 3820) && (ape_ctx->CRC & 0x80000000)) { + ape_ctx->CRC &= ~0x80000000; + + ape_ctx->frameflags = read_byte(); + ape_ctx->frameflags = (ape_ctx->frameflags << 8) | read_byte(); + ape_ctx->frameflags = (ape_ctx->frameflags << 8) | read_byte(); + ape_ctx->frameflags = (ape_ctx->frameflags << 8) | read_byte(); + } + /* Keep a count of the blocks decoded in this frame */ + ape_ctx->blocksdecoded = 0; + + /* Initialise the rice structs */ + riceX.k = 10; + riceX.ksum = (1 << riceX.k) * 16; + riceY.k = 10; + riceY.ksum = (1 << riceY.k) * 16; + + /* The first 8 bits of input are ignored. */ + skip_byte(); + + range_start_decoding(); + + /* Return the new state of the buffer */ + *bytesconsumed = (intptr_t)bytebuffer - (intptr_t)inbuffer; + *firstbyte = bytebufferoffset; +} + +int entropy_decode(struct ape_ctx_t* ape_ctx, + unsigned char* inbuffer, int* firstbyte, + int* bytesconsumed, + int32_t* decoded0, int32_t* decoded1, + int blockstodecode) +{ + bytebuffer = inbuffer; + bytebufferoffset = *firstbyte; + + ape_ctx->blocksdecoded += blockstodecode; + + if (ape_ctx->frameflags & APE_FRAMECODE_STEREO_SILENCE) { + /* We are pure silence, just memset the output buffer. */ + memset(decoded0, 0, blockstodecode * sizeof(int32_t)); + memset(decoded1, 0, blockstodecode * sizeof(int32_t)); + } else { + if (ape_ctx->fileversion > 3970) { + while (blockstodecode--) { + *(decoded0++) = entropy_decode3980(&riceY); + if (decoded1 != NULL) + *(decoded1++) = entropy_decode3980(&riceX); + } + } else { + while (blockstodecode--) { + *(decoded0++) = entropy_decode3970(&riceY); + if (decoded1 != NULL) + *(decoded1++) = entropy_decode3970(&riceX); + } + } + } + + if (ape_ctx->blocksdecoded == ape_ctx->currentframeblocks) + { + range_done_decoding(); + } + + /* Return the new state of the buffer */ + *bytesconsumed = bytebuffer - inbuffer; + *firstbyte = bytebufferoffset; + + return(0); +} diff --git a/apps/codecs/demac/libdemac/entropy.h b/apps/codecs/demac/libdemac/entropy.h new file mode 100644 index 0000000000..dd6736cb15 --- /dev/null +++ b/apps/codecs/demac/libdemac/entropy.h @@ -0,0 +1,40 @@ +/* + +libdemac - A Monkey's Audio decoder + +$Id:$ + +Copyright (C) Dave Chapman 2007 + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA + +*/ + +#ifndef _APE_ENTROPY_H +#define _APE_ENTROPY_H + +#include + +void init_entropy_decoder(struct ape_ctx_t* ape_ctx, + unsigned char* inbuffer, int* firstbyte, + int* bytesconsumed); + +int entropy_decode(struct ape_ctx_t* ape_ctx, + unsigned char* inbuffer, int* firstbyte, + int* bytesconsumed, + int32_t* decoded0, int32_t* decoded1, + int blockstodecode); + +#endif diff --git a/apps/codecs/demac/libdemac/filter.c b/apps/codecs/demac/libdemac/filter.c new file mode 100644 index 0000000000..76faa67aa7 --- /dev/null +++ b/apps/codecs/demac/libdemac/filter.c @@ -0,0 +1,215 @@ +/* + +libdemac - A Monkey's Audio decoder + +$Id:$ + +Copyright (C) Dave Chapman 2007 + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA + +*/ + +#include +#include + +#include "demac.h" +#include "filter.h" + +#include "vector_math16.h" + +struct filter_t { + int16_t* coeffs; /* ORDER entries */ + + /* We store all the filter delays in a single buffer */ + int16_t* historybuffer; /* ORDER*2 + HISTORY_SIZE entries */ + + int16_t* delay; + int16_t* adaptcoeffs; + + int avg; +}; + +/* We name the functions according to the ORDER and FRACBITS + pre-processor symbols and build multiple .o files from this .c file + - this increases code-size but gives the compiler more scope for + optimising the individual functions, as well as replacing a lot of + variables with constants. +*/ + +#if FRACBITS == 11 + #if ORDER == 16 + #define INIT_FILTER init_filter_16_11 + #define APPLY_FILTER apply_filter_16_11 + #elif ORDER == 64 + #define INIT_FILTER init_filter_64_11 + #define APPLY_FILTER apply_filter_64_11 + #endif +#elif FRACBITS == 13 + #define INIT_FILTER init_filter_256_13 + #define APPLY_FILTER apply_filter_256_13 +#elif FRACBITS == 10 + #define INIT_FILTER init_filter_32_10 + #define APPLY_FILTER apply_filter_32_10 +#elif FRACBITS == 15 + #define INIT_FILTER init_filter_1280_15 + #define APPLY_FILTER apply_filter_1280_15 +#endif + +/* Some macros to handle the fixed-point stuff */ + +#define FP_HALF (1 << (FRACBITS - 1)) /* 0.5 in fixed-point format. */ +#define FP_TO_INT(x) ((x + FP_HALF) >> FRACBITS); /* round(x) */ + +#define SATURATE(x) (int16_t)(((x) == (int16_t)(x)) ? (x) : ((x) >> 31) ^ 0x7FFF); + +/* Apply the filter with state f to count entries in data[] */ + +static inline void do_apply_filter_3980(struct filter_t* f, int32_t* data, int count) +{ + int res; + int absres; + + while(count--) + { + res = FP_TO_INT(scalarproduct(f->delay - ORDER, f->coeffs)); + + if (*data < 0) + vector_add(f->coeffs, f->adaptcoeffs - ORDER); + else if (*data > 0) + vector_sub(f->coeffs, f->adaptcoeffs - ORDER); + + /* Convert res from (32-FRACBITS).FRACBITS fixed-point format to an + integer (rounding to nearest) and add the input value to + it */ + res += *data; + + *data++ = res; + + /* Update the output history */ + *f->delay++ = SATURATE(res); + + /* Version 3.98 and later files */ + + /* Update the adaption coefficients */ + absres = (res < 0 ? -res : res); + + if (absres > (f->avg * 3)) + *f->adaptcoeffs = ((res >> 25) & 64) - 32; + else if (absres > (f->avg * 4) / 3) + *f->adaptcoeffs = ((res >> 26) & 32) - 16; + else if (absres > 0) + *f->adaptcoeffs = ((res >> 27) & 16) - 8; + else + *f->adaptcoeffs = 0; + + f->avg += (absres - f->avg) / 16; + + f->adaptcoeffs[-1] >>= 1; + f->adaptcoeffs[-2] >>= 1; + f->adaptcoeffs[-8] >>= 1; + + f->adaptcoeffs++; + + /* Have we filled the history buffer? */ + if (f->delay == f->historybuffer + HISTORY_SIZE + (ORDER*2)) { + memmove(f->historybuffer, f->delay - (ORDER*2), + (ORDER*2) * sizeof(int16_t)); + f->delay = f->historybuffer + ORDER*2; + f->adaptcoeffs = f->historybuffer + ORDER; + } + } +} + +static inline void do_apply_filter_3970(struct filter_t* f, int32_t* data, int count) +{ + int res; + + while(count--) + { + res = FP_TO_INT(scalarproduct(f->delay - ORDER, f->coeffs)); + + if (*data < 0) + vector_add(f->coeffs, f->adaptcoeffs - ORDER); + else if (*data > 0) + vector_sub(f->coeffs, f->adaptcoeffs - ORDER); + + /* Convert res from (32-FRACBITS).FRACBITS fixed-point format to an + integer (rounding to nearest) and add the input value to + it */ + res += *data; + + *data++ = res; + + /* Update the output history */ + *f->delay++ = SATURATE(res); + + /* Version ??? to < 3.98 files (untested) */ + f->adaptcoeffs[0] = (res == 0) ? 0 : ((res >> 28) & 8) - 4; + f->adaptcoeffs[-4] >>= 1; + f->adaptcoeffs[-8] >>= 1; + + f->adaptcoeffs++; + + /* Have we filled the history buffer? */ + if (f->delay == f->historybuffer + HISTORY_SIZE + (ORDER*2)) { + memmove(f->historybuffer, f->delay - (ORDER*2), + (ORDER*2) * sizeof(int16_t)); + f->delay = f->historybuffer + ORDER*2; + f->adaptcoeffs = f->historybuffer + ORDER; + } + } +} + +static struct filter_t filter0 IBSS_ATTR; +static struct filter_t filter1 IBSS_ATTR; + +static void do_init_filter(struct filter_t* f, int16_t* buf) +{ + f->coeffs = buf; + f->historybuffer = buf + ORDER; + + /* Zero the output history buffer */ + memset(f->historybuffer, 0 , (ORDER*2) * sizeof(int16_t)); + f->delay = f->historybuffer + ORDER*2; + f->adaptcoeffs = f->historybuffer + ORDER; + + /* Zero the co-efficients */ + memset(f->coeffs, 0, ORDER * sizeof(int16_t)); + + /* Zero the running average */ + f->avg = 0; +} + +void INIT_FILTER(int16_t* buf) +{ + do_init_filter(&filter0, buf); + do_init_filter(&filter1, buf + ORDER * 3 + HISTORY_SIZE); +} + +int APPLY_FILTER(int fileversion, int32_t* data0, int32_t* data1, int count) +{ + if (fileversion >= 3980) { + do_apply_filter_3980(&filter0, data0, count); + if (data1 != NULL) + do_apply_filter_3980(&filter1, data1, count); + } else { + do_apply_filter_3970(&filter0, data0, count); + if (data1 != NULL) + do_apply_filter_3970(&filter1, data1, count); + } + + return 0; +} diff --git a/apps/codecs/demac/libdemac/filter.h b/apps/codecs/demac/libdemac/filter.h new file mode 100644 index 0000000000..b98403cfc8 --- /dev/null +++ b/apps/codecs/demac/libdemac/filter.h @@ -0,0 +1,48 @@ +/* + +libdemac - A Monkey's Audio decoder + +$Id:$ + +Copyright (C) Dave Chapman 2007 + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA + +*/ + +#ifndef _APE_FILTER_H +#define _APE_FILTER_H + +#include + +/* The size of the history buffers */ +#define HISTORY_SIZE 512 + +void init_filter_16_11(int16_t* buf); +int apply_filter_16_11(int fileversion, int32_t* decoded0, int32_t* decoded1, int count); + +void init_filter_64_11(int16_t* buf); +int apply_filter_64_11(int fileversion, int32_t* decoded0, int32_t* decoded1, int count); + +void init_filter_32_10(int16_t* buf); +int apply_filter_32_10(int fileversion, int32_t* decoded0, int32_t* decoded1, int count); + +void init_filter_256_13(int16_t* buf); +int apply_filter_256_13(int fileversion, int32_t* decoded0, int32_t* decoded1, int count); + +void init_filter_1280_15(int16_t* buf); +int apply_filter_1280_15(int fileversion, int32_t* decoded0, int32_t* decoded1, int count); + +#endif diff --git a/apps/codecs/demac/libdemac/filter_1280_15.c b/apps/codecs/demac/libdemac/filter_1280_15.c new file mode 100644 index 0000000000..edf1ce1bb1 --- /dev/null +++ b/apps/codecs/demac/libdemac/filter_1280_15.c @@ -0,0 +1,27 @@ +/* + +libdemac - A Monkey's Audio decoder + +$Id:$ + +Copyright (C) Dave Chapman 2007 + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA + +*/ + +#define ORDER 1280 +#define FRACBITS 15 +#include "filter.c" diff --git a/apps/codecs/demac/libdemac/filter_16_11.c b/apps/codecs/demac/libdemac/filter_16_11.c new file mode 100644 index 0000000000..07e4b96dc2 --- /dev/null +++ b/apps/codecs/demac/libdemac/filter_16_11.c @@ -0,0 +1,27 @@ +/* + +libdemac - A Monkey's Audio decoder + +$Id:$ + +Copyright (C) Dave Chapman 2007 + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA + +*/ + +#define ORDER 16 +#define FRACBITS 11 +#include "filter.c" diff --git a/apps/codecs/demac/libdemac/filter_256_13.c b/apps/codecs/demac/libdemac/filter_256_13.c new file mode 100644 index 0000000000..370dec1d5a --- /dev/null +++ b/apps/codecs/demac/libdemac/filter_256_13.c @@ -0,0 +1,27 @@ +/* + +libdemac - A Monkey's Audio decoder + +$Id:$ + +Copyright (C) Dave Chapman 2007 + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA + +*/ + +#define ORDER 256 +#define FRACBITS 13 +#include "filter.c" diff --git a/apps/codecs/demac/libdemac/filter_32_10.c b/apps/codecs/demac/libdemac/filter_32_10.c new file mode 100644 index 0000000000..b585de98a4 --- /dev/null +++ b/apps/codecs/demac/libdemac/filter_32_10.c @@ -0,0 +1,27 @@ +/* + +libdemac - A Monkey's Audio decoder + +$Id:$ + +Copyright (C) Dave Chapman 2007 + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA + +*/ + +#define ORDER 32 +#define FRACBITS 10 +#include "filter.c" diff --git a/apps/codecs/demac/libdemac/filter_64_11.c b/apps/codecs/demac/libdemac/filter_64_11.c new file mode 100644 index 0000000000..8b8d326d1d --- /dev/null +++ b/apps/codecs/demac/libdemac/filter_64_11.c @@ -0,0 +1,27 @@ +/* + +libdemac - A Monkey's Audio decoder + +$Id:$ + +Copyright (C) Dave Chapman 2007 + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA + +*/ + +#define ORDER 64 +#define FRACBITS 11 +#include "filter.c" diff --git a/apps/codecs/demac/libdemac/parser.c b/apps/codecs/demac/libdemac/parser.c new file mode 100644 index 0000000000..bcb542dbb6 --- /dev/null +++ b/apps/codecs/demac/libdemac/parser.c @@ -0,0 +1,357 @@ +/* + +libdemac - A Monkey's Audio decoder + +$Id:$ + +Copyright (C) Dave Chapman 2007 + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA + +*/ + +#include +#include +#ifndef ROCKBOX +#include +#include +#include +#include +#include +#include +#endif + +#include "parser.h" + + +static inline int16_t get_int16(unsigned char* buf) +{ + return(buf[0] | (buf[1] << 8)); +} + +static inline uint16_t get_uint16(unsigned char* buf) +{ + return(buf[0] | (buf[1] << 8)); +} + +static inline uint32_t get_uint32(unsigned char* buf) +{ + return(buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24)); +} + + +int ape_parseheaderbuf(unsigned char* buf, struct ape_ctx_t* ape_ctx) +{ + unsigned char* header; + + memset(ape_ctx,0,sizeof(struct ape_ctx_t)); + /* TODO: Skip any leading junk such as id3v2 tags */ + ape_ctx->junklength = 0; + + memcpy(ape_ctx->magic, buf, 4); + if (memcmp(ape_ctx->magic,"MAC ",4)!=0) + { + return -1; + } + + ape_ctx->fileversion = get_int16(buf + 4); + + if (ape_ctx->fileversion >= 3980) + { + ape_ctx->padding1 = get_int16(buf + 6); + ape_ctx->descriptorlength = get_uint32(buf + 8); + ape_ctx->headerlength = get_uint32(buf + 12); + ape_ctx->seektablelength = get_uint32(buf + 16); + ape_ctx->wavheaderlength = get_uint32(buf + 20); + ape_ctx->audiodatalength = get_uint32(buf + 24); + ape_ctx->audiodatalength_high = get_uint32(buf + 28); + ape_ctx->wavtaillength = get_uint32(buf + 32); + memcpy(ape_ctx->md5, buf + 36, 16); + + header = buf + ape_ctx->descriptorlength; + + /* Read header data */ + ape_ctx->compressiontype = get_uint16(header + 0); + ape_ctx->formatflags = get_uint16(header + 2); + ape_ctx->blocksperframe = get_uint32(header + 4); + ape_ctx->finalframeblocks = get_uint32(header + 8); + ape_ctx->totalframes = get_uint32(header + 12); + ape_ctx->bps = get_uint16(header + 16); + ape_ctx->channels = get_uint16(header + 18); + ape_ctx->samplerate = get_uint32(header + 20); + + ape_ctx->firstframe = ape_ctx->junklength + ape_ctx->descriptorlength + + ape_ctx->headerlength + ape_ctx->seektablelength + + ape_ctx->wavheaderlength; + } else { + ape_ctx->compressiontype = get_uint16(buf + 6); + ape_ctx->formatflags = get_uint16(buf + 8); + ape_ctx->channels = get_uint16(buf + 10); + ape_ctx->samplerate = get_uint32(buf + 14); + ape_ctx->wavheaderlength = get_uint32(buf + 18); + ape_ctx->totalframes = get_uint32(buf + 26); + ape_ctx->finalframeblocks = get_uint32(buf + 30); + } + + ape_ctx->totalsamples = ape_ctx->finalframeblocks; + if (ape_ctx->totalframes > 1) + ape_ctx->totalsamples += ape_ctx->blocksperframe * (ape_ctx->totalframes-1); + + /* TODO: Parse and store seektable */ + + return 0; +} + + +#ifndef ROCKBOX +/* Helper functions */ + +static int read_uint16(int fd, uint16_t* x) +{ + unsigned char tmp[2]; + int n; + + n = read(fd,tmp,2); + + if (n != 2) + return -1; + + *x = tmp[0] | (tmp[1] << 8); + + return 0; +} + +static int read_int16(int fd, int16_t* x) +{ + return read_uint16(fd, (uint16_t*)x); +} + +static int read_uint32(int fd, uint32_t* x) +{ + unsigned char tmp[4]; + int n; + + n = read(fd,tmp,4); + + if (n != 4) + return -1; + + *x = tmp[0] | (tmp[1] << 8) | (tmp[2] << 16) | (tmp[3] << 24); + + return 0; +} + +int ape_parseheader(int fd, struct ape_ctx_t* ape_ctx) +{ + int i,n; + + /* TODO: Skip any leading junk such as id3v2 tags */ + ape_ctx->junklength = 0; + + lseek(fd,ape_ctx->junklength,SEEK_SET); + + n = read(fd,&ape_ctx->magic,4); + if (n != 4) return -1; + + if (memcmp(ape_ctx->magic,"MAC ",4)!=0) + { + return -1; + } + + if (read_int16(fd,&ape_ctx->fileversion) < 0) + return -1; + + if (ape_ctx->fileversion >= 3980) + { + if (read_int16(fd,&ape_ctx->padding1) < 0) + return -1; + if (read_uint32(fd,&ape_ctx->descriptorlength) < 0) + return -1; + if (read_uint32(fd,&ape_ctx->headerlength) < 0) + return -1; + if (read_uint32(fd,&ape_ctx->seektablelength) < 0) + return -1; + if (read_uint32(fd,&ape_ctx->wavheaderlength) < 0) + return -1; + if (read_uint32(fd,&ape_ctx->audiodatalength) < 0) + return -1; + if (read_uint32(fd,&ape_ctx->audiodatalength_high) < 0) + return -1; + if (read_uint32(fd,&ape_ctx->wavtaillength) < 0) + return -1; + if (read(fd,&ape_ctx->md5,16) != 16) + return -1; + + /* Skip any unknown bytes at the end of the descriptor. This is for future + compatibility */ + if (ape_ctx->descriptorlength > 52) + lseek(fd,ape_ctx->descriptorlength - 52, SEEK_CUR); + + /* Read header data */ + if (read_uint16(fd,&ape_ctx->compressiontype) < 0) + return -1; + if (read_uint16(fd,&ape_ctx->formatflags) < 0) + return -1; + if (read_uint32(fd,&ape_ctx->blocksperframe) < 0) + return -1; + if (read_uint32(fd,&ape_ctx->finalframeblocks) < 0) + return -1; + if (read_uint32(fd,&ape_ctx->totalframes) < 0) + return -1; + if (read_uint16(fd,&ape_ctx->bps) < 0) + return -1; + if (read_uint16(fd,&ape_ctx->channels) < 0) + return -1; + if (read_uint32(fd,&ape_ctx->samplerate) < 0) + return -1; + } else { + ape_ctx->descriptorlength = 0; + ape_ctx->headerlength = 32; + + if (read_uint16(fd,&ape_ctx->compressiontype) < 0) + return -1; + if (read_uint16(fd,&ape_ctx->formatflags) < 0) + return -1; + if (read_uint16(fd,&ape_ctx->channels) < 0) + return -1; + if (read_uint32(fd,&ape_ctx->samplerate) < 0) + return -1; + if (read_uint32(fd,&ape_ctx->wavheaderlength) < 0) + return -1; + if (read_uint32(fd,&ape_ctx->wavtaillength) < 0) + return -1; + if (read_uint32(fd,&ape_ctx->totalframes) < 0) + return -1; + if (read_uint32(fd,&ape_ctx->finalframeblocks) < 0) + return -1; + + if (ape_ctx->formatflags & MAC_FORMAT_FLAG_HAS_PEAK_LEVEL) + { + lseek(fd, 4, SEEK_CUR); /* Skip the peak level */ + ape_ctx->headerlength += 4; + } + + if (ape_ctx->formatflags & MAC_FORMAT_FLAG_HAS_SEEK_ELEMENTS) + { + if (read_uint32(fd,&ape_ctx->seektablelength) < 0) + return -1; + ape_ctx->headerlength += 4; + ape_ctx->seektablelength *= sizeof(int32_t); + } else { + ape_ctx->seektablelength = ape_ctx->totalframes * sizeof(int32_t); + } + + if (ape_ctx->formatflags & MAC_FORMAT_FLAG_8_BIT) + ape_ctx->bps = 8; + else if (ape_ctx->formatflags & MAC_FORMAT_FLAG_24_BIT) + ape_ctx->bps = 24; + else + ape_ctx->bps = 16; + + if (ape_ctx->fileversion >= 3950) + ape_ctx->blocksperframe = 73728 * 4; + else if ((ape_ctx->fileversion >= 3900) || (ape_ctx->fileversion >= 3800 && ape_ctx->compressiontype >= 4000)) + ape_ctx->blocksperframe = 73728; + else + ape_ctx->blocksperframe = 9216; + + /* Skip any stored wav header */ + if (!(ape_ctx->formatflags & MAC_FORMAT_FLAG_CREATE_WAV_HEADER)) + { + lseek(fd, ape_ctx->wavheaderlength, SEEK_CUR); + } + } + + ape_ctx->totalsamples = ape_ctx->finalframeblocks; + if (ape_ctx->totalframes > 1) + ape_ctx->totalsamples += ape_ctx->blocksperframe * (ape_ctx->totalframes-1); + + if (ape_ctx->seektablelength > 0) + { + ape_ctx->seektable = malloc(ape_ctx->seektablelength); + if (ape_ctx->seektable == NULL) + return -1; + for (i=0; i < ape_ctx->seektablelength / sizeof(uint32_t); i++) + { + if (read_uint32(fd,&ape_ctx->seektable[i]) < 0) + { + free(ape_ctx->seektable); + return -1; + } + } + } + + ape_ctx->firstframe = ape_ctx->junklength + ape_ctx->descriptorlength + + ape_ctx->headerlength + ape_ctx->seektablelength + + ape_ctx->wavheaderlength; + + return 0; +} + +void ape_dumpinfo(struct ape_ctx_t* ape_ctx) +{ + int i; + + printf("Descriptor Block:\n\n"); + printf("magic = \"%c%c%c%c\"\n", + ape_ctx->magic[0],ape_ctx->magic[1], + ape_ctx->magic[2],ape_ctx->magic[3]); + printf("fileversion = %d\n",ape_ctx->fileversion); + printf("descriptorlength = %d\n",ape_ctx->descriptorlength); + printf("headerlength = %d\n",ape_ctx->headerlength); + printf("seektablelength = %d\n",ape_ctx->seektablelength); + printf("wavheaderlength = %d\n",ape_ctx->wavheaderlength); + printf("audiodatalength = %d\n",ape_ctx->audiodatalength); + printf("audiodatalength_high = %d\n",ape_ctx->audiodatalength_high); + printf("wavtaillength = %d\n",ape_ctx->wavtaillength); + printf("md5 = "); + for (i = 0; i < 16; i++) + printf("%02x",ape_ctx->md5[i]); + printf("\n"); + + printf("\nHeader Block:\n\n"); + + printf("compressiontype = %d\n",ape_ctx->compressiontype); + printf("formatflags = %d\n",ape_ctx->formatflags); + printf("blocksperframe = %d\n",ape_ctx->blocksperframe); + printf("finalframeblocks = %d\n",ape_ctx->finalframeblocks); + printf("totalframes = %d\n",ape_ctx->totalframes); + printf("bps = %d\n",ape_ctx->bps); + printf("channels = %d\n",ape_ctx->channels); + printf("samplerate = %d\n",ape_ctx->samplerate); + + printf("\nSeektable\n\n"); + if ((ape_ctx->seektablelength / sizeof(uint32_t)) != ape_ctx->totalframes) + { + printf("No seektable\n"); + } + else + { + for ( i = 0; i < ape_ctx->seektablelength / sizeof(uint32_t) ; i++) + { + if (i < ape_ctx->totalframes-1) { + printf("%8d %d (%d bytes)\n",i,ape_ctx->seektable[i],ape_ctx->seektable[i+1]-ape_ctx->seektable[i]); + } else { + printf("%8d %d\n",i,ape_ctx->seektable[i]); + } + } + } + printf("\nCalculated information:\n\n"); + printf("junklength = %d\n",ape_ctx->junklength); + printf("firstframe = %d\n",ape_ctx->firstframe); + printf("totalsamples = %d\n",ape_ctx->totalsamples); +} + +#endif /* !ROCKBOX */ diff --git a/apps/codecs/demac/libdemac/parser.h b/apps/codecs/demac/libdemac/parser.h new file mode 100644 index 0000000000..edf4222fd5 --- /dev/null +++ b/apps/codecs/demac/libdemac/parser.h @@ -0,0 +1,137 @@ +/* + +libdemac - A Monkey's Audio decoder + +$Id:$ + +Copyright (C) Dave Chapman 2007 + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA + +*/ + +#ifndef _APE_PARSER_H +#define _APE_PARSER_H + +#include + +#ifdef ROCKBOX +/* Include the Rockbox Codec API when building for Rockbox */ +#define APE_OUTPUT_DEPTH 29 +#ifndef ROCKBOX_PLUGIN +#include "../lib/codeclib.h" +#include +#endif +#else +#define APE_OUTPUT_DEPTH (ape_ctx->bps) +#define IBSS_ATTR +#define ICONST_ATTR +#define ICODE_ATTR +#endif + +/* The earliest and latest file formats supported by this library */ +#define APE_MIN_VERSION 3970 +#define APE_MAX_VERSION 3990 + +#define MAC_FORMAT_FLAG_8_BIT 1 // is 8-bit [OBSOLETE] +#define MAC_FORMAT_FLAG_CRC 2 // uses the new CRC32 error detection [OBSOLETE] +#define MAC_FORMAT_FLAG_HAS_PEAK_LEVEL 4 // uint32 nPeakLevel after the header [OBSOLETE] +#define MAC_FORMAT_FLAG_24_BIT 8 // is 24-bit [OBSOLETE] +#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) + + +/* Special frame codes: + + MONO_SILENCE - All PCM samples in frame are zero (mono streams only) + LEFT_SILENCE - All PCM samples for left channel in frame are zero (stereo streams) + RIGHT_SILENCE - All PCM samples for left channel in frame are zero (stereo streams) + PSEUDO_STEREO - Left and Right channels are identical + +*/ + +#define APE_FRAMECODE_MONO_SILENCE 1 +#define APE_FRAMECODE_STEREO_SILENCE 3 +#define APE_FRAMECODE_PSEUDO_STEREO 4 + +#define HISTORY_SIZE 512 +#define PREDICTOR_ORDER 8 + +struct predictor_t +{ + /* Adaption co-efficients */ + int32_t coeffsA[4]; + int32_t coeffsB[5]; + + /* Filter histories */ + int32_t historybuffer[HISTORY_SIZE + PREDICTOR_ORDER * 4]; + int32_t* delayA; + int32_t* delayB; + int32_t* adaptcoeffsA; + int32_t* adaptcoeffsB; + + int32_t lastA; + + int32_t filterA; + int32_t filterB; +}; + +struct ape_ctx_t +{ + /* Derived fields */ + uint32_t junklength; + uint32_t firstframe; + uint32_t totalsamples; + + /* Info from Descriptor Block */ + char magic[4]; + int16_t fileversion; + int16_t padding1; + uint32_t descriptorlength; + uint32_t headerlength; + uint32_t seektablelength; + uint32_t wavheaderlength; + uint32_t audiodatalength; + uint32_t audiodatalength_high; + uint32_t wavtaillength; + uint8_t md5[16]; + + /* Info from Header Block */ + uint16_t compressiontype; + uint16_t formatflags; + uint32_t blocksperframe; + uint32_t finalframeblocks; + uint32_t totalframes; + uint16_t bps; + uint16_t channels; + uint32_t samplerate; + + /* Seektable */ + uint32_t* seektable; + + /* Decoder state */ + uint32_t CRC; + int frameflags; + int currentframeblocks; + int blocksdecoded; + struct predictor_t predictorY; + struct predictor_t predictorX; +}; + +int ape_parseheader(int fd, struct ape_ctx_t* ape_ctx); +int ape_parseheaderbuf(unsigned char* buf, struct ape_ctx_t* ape_ctx); +void ape_dumpinfo(struct ape_ctx_t* ape_ctx); + +#endif diff --git a/apps/codecs/demac/libdemac/predictor.c b/apps/codecs/demac/libdemac/predictor.c new file mode 100644 index 0000000000..ef72fedfbd --- /dev/null +++ b/apps/codecs/demac/libdemac/predictor.c @@ -0,0 +1,196 @@ +/* + +libdemac - A Monkey's Audio decoder + +$Id:$ + +Copyright (C) Dave Chapman 2007 + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA + +*/ + +#include +#include + +#include "parser.h" +#include "predictor.h" + +#include "vector_math32.h" + +/* Return 0 if x is zero, -1 if x is positive, 1 if x is negative */ +#define SIGN(x) (x) ? (((x) > 0) ? -1 : 1) : 0 + +static const int32_t initial_coeffs[4] = { + 360, 317, -109, 98 +}; + +static void init_predictor(struct predictor_t* p) +{ + /* Zero the history buffers */ + memset(p->historybuffer, 0, (PREDICTOR_ORDER*4) * sizeof(int32_t)); + p->delayA = p->historybuffer + PREDICTOR_ORDER*4; + p->delayB = p->historybuffer + PREDICTOR_ORDER*3; + p->adaptcoeffsA = p->historybuffer + PREDICTOR_ORDER*2; + p->adaptcoeffsB = p->historybuffer + PREDICTOR_ORDER; + + /* Initialise and zero the co-efficients */ + memcpy(p->coeffsA, initial_coeffs, sizeof(initial_coeffs)); + memset(p->coeffsB, 0, sizeof(p->coeffsB)); + + p->filterA = 0; + p->filterB = 0; + + p->lastA = 0; +} + +static int do_predictor_decode(struct predictor_t* p, int32_t A, int32_t B) +{ + int32_t predictionA, predictionB, currentA; + + p->delayA[0] = p->lastA; + p->delayA[-1] = p->delayA[0] - p->delayA[-1]; + + predictionA = scalarproduct4_rev32(p->coeffsA,p->delayA); + + /* Apply a scaled first-order filter compression */ + p->delayB[0] = B - ((p->filterB * 31) >> 5); + p->filterB = B; + + p->delayB[-1] = p->delayB[0] - p->delayB[-1]; + + predictionB = scalarproduct5_rev32(p->coeffsB,p->delayB); + + currentA = A + ((predictionA + (predictionB >> 1)) >> 10); + + p->adaptcoeffsA[0] = SIGN(p->delayA[0]); + p->adaptcoeffsA[-1] = SIGN(p->delayA[-1]); + + p->adaptcoeffsB[0] = SIGN(p->delayB[0]); + p->adaptcoeffsB[-1] = SIGN(p->delayB[-1]); + + if (A > 0) + { + vector_sub4_rev32(p->coeffsA, p->adaptcoeffsA); + vector_sub5_rev32(p->coeffsB, p->adaptcoeffsB); + } + else if (A < 0) + { + vector_add4_rev32(p->coeffsA, p->adaptcoeffsA); + vector_add5_rev32(p->coeffsB, p->adaptcoeffsB); + } + + p->delayA++; + p->delayB++; + p->adaptcoeffsA++; + p->adaptcoeffsB++; + + /* Have we filled the history buffer? */ + if (p->delayA == p->historybuffer + HISTORY_SIZE + (PREDICTOR_ORDER*4)) { + memmove(p->historybuffer, p->delayA - (PREDICTOR_ORDER*4), + (PREDICTOR_ORDER*4) * sizeof(int32_t)); + p->delayA = p->historybuffer + PREDICTOR_ORDER*4; + p->delayB = p->historybuffer + PREDICTOR_ORDER*3; + p->adaptcoeffsA = p->historybuffer + PREDICTOR_ORDER*2; + p->adaptcoeffsB = p->historybuffer + PREDICTOR_ORDER; + } + + p->lastA = currentA; + p->filterA = currentA + ((p->filterA * 31) >> 5); + + return p->filterA; +} + +static int32_t X; + +void init_predictor_decoder(struct ape_ctx_t* ape_ctx) +{ + X = 0; + + init_predictor(&ape_ctx->predictorY); + init_predictor(&ape_ctx->predictorX); +} + +int predictor_decode_stereo(struct ape_ctx_t* ape_ctx, int32_t* decoded0, int32_t* decoded1, int count) ICODE_ATTR; +int predictor_decode_stereo(struct ape_ctx_t* ape_ctx, int32_t* decoded0, int32_t* decoded1, int count) +{ + while (count--) + { + *decoded0 = do_predictor_decode(&ape_ctx->predictorY, *decoded0, X); + X = do_predictor_decode(&ape_ctx->predictorX, *decoded1, *(decoded0)++); + *(decoded1++) = X; + } + + return 0; +} + +int predictor_decode_mono(struct ape_ctx_t* ape_ctx, int32_t* decoded0, int count) +{ + struct predictor_t* p = &ape_ctx->predictorY; + int32_t predictionA, currentA, A; + + currentA = p->lastA; + + while (count--) + { + A = *decoded0; + + p->delayA[0] = currentA; + p->delayA[-1] = p->delayA[0] - p->delayA[-1]; + + predictionA = (p->delayA[0] * p->coeffsA[0]) + + (p->delayA[-1] * p->coeffsA[1]) + + (p->delayA[-2] * p->coeffsA[2]) + + (p->delayA[-3] * p->coeffsA[3]); + + currentA = A + (predictionA >> 10); + + p->adaptcoeffsA[0] = SIGN(p->delayA[0]); + p->adaptcoeffsA[-1] = SIGN(p->delayA[-1]); + + if (A > 0) + { + p->coeffsA[0] -= p->adaptcoeffsA[0]; + p->coeffsA[1] -= p->adaptcoeffsA[-1]; + p->coeffsA[2] -= p->adaptcoeffsA[-2]; + p->coeffsA[3] -= p->adaptcoeffsA[-3]; + } + else if (A < 0) + { + p->coeffsA[0] += p->adaptcoeffsA[0]; + p->coeffsA[1] += p->adaptcoeffsA[-1]; + p->coeffsA[2] += p->adaptcoeffsA[-2]; + p->coeffsA[3] += p->adaptcoeffsA[-3]; + } + + p->delayA++; + p->adaptcoeffsA++; + + /* Have we filled the history buffer? */ + if (p->delayA == p->historybuffer + HISTORY_SIZE + (PREDICTOR_ORDER*4)) { + memmove(p->historybuffer, p->delayA - (PREDICTOR_ORDER*4), + (PREDICTOR_ORDER*4) * sizeof(int32_t)); + p->delayA = p->historybuffer + PREDICTOR_ORDER*4; + p->adaptcoeffsA = p->historybuffer + PREDICTOR_ORDER*2; + } + + p->filterA = currentA + ((p->filterA * 31) >> 5); + *(decoded0++) = p->filterA; + } + + p->lastA = currentA; + + return 0; +} diff --git a/apps/codecs/demac/libdemac/predictor.h b/apps/codecs/demac/libdemac/predictor.h new file mode 100644 index 0000000000..3c023c8188 --- /dev/null +++ b/apps/codecs/demac/libdemac/predictor.h @@ -0,0 +1,36 @@ +/* + +libdemac - A Monkey's Audio decoder + +$Id:$ + +Copyright (C) Dave Chapman 2007 + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA + +*/ + +#ifndef _APE_PREDICTOR_H +#define _APE_PREDICTOR_H + +#include +#include "parser.h" +#include "filter.h" + +void init_predictor_decoder(struct ape_ctx_t* ape_ctx); +int predictor_decode_stereo(struct ape_ctx_t* ape_ctx, int32_t* decoded0, int32_t* decoded1, int count); +int predictor_decode_mono(struct ape_ctx_t* ape_ctx, int32_t* decoded0, int count); + +#endif diff --git a/apps/codecs/demac/libdemac/rangecoding.h b/apps/codecs/demac/libdemac/rangecoding.h new file mode 100644 index 0000000000..8be5e923ba --- /dev/null +++ b/apps/codecs/demac/libdemac/rangecoding.h @@ -0,0 +1,180 @@ +/* + +libdemac - A Monkey's Audio decoder + +$Id:$ + +Copyright (C) Dave Chapman 2007 + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA + +*/ + +/* + +Range decoder adapted from rangecod.c included in: + + http://www.compressconsult.com/rangecoder/rngcod13.zip + + rangecod.c range encoding + + (c) Michael Schindler + 1997, 1998, 1999, 2000 + http://www.compressconsult.com/ + michael@compressconsult.com + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + +The encoding functions were removed, and functions turned into "static +inline" functions and moved to a .h file. Some minor cosmetic changes +were made (e.g. turning pre-processor symbols into upper-case, +removing the rc parameter from each function (and the RNGC macro)). + + +*/ + + +/* BITSTREAM READING FUNCTIONS */ + +/* We deal with the input data one byte at a time - to ensure + functionality on CPUs of any endianness regardless of any requirements + for aligned reads. +*/ + +static unsigned char* bytebuffer IBSS_ATTR; +static int bytebufferoffset IBSS_ATTR; + +static inline void skip_byte(void) +{ + if (bytebufferoffset) { + bytebufferoffset--; + } else { + bytebufferoffset = 3; + bytebuffer += 4; + } +} + +static inline int read_byte(void) +{ + int ch = bytebuffer[bytebufferoffset]; + + skip_byte(); + + return ch; +} + +/* RANGE DECODING FUNCTIONS */ + +/* SIZE OF RANGE ENCODING CODE VALUES. */ + +#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) + +struct rangecoder_t +{ + uint32_t low; /* low end of interval */ + uint32_t range; /* length of interval */ + uint32_t help; /* bytes_to_follow resp. intermediate value */ + unsigned int buffer; /* buffer for input/output */ +}; + +static struct rangecoder_t rc; + +/* Start the decoder */ +static inline void range_start_decoding(void) +{ + rc.buffer = read_byte(); + rc.low = rc.buffer >> (8 - EXTRA_BITS); + rc.range = (uint32_t) 1 << EXTRA_BITS; +} + +static inline void range_dec_normalize(void) +{ + while (rc.range <= BOTTOM_VALUE) + { + rc.buffer = (rc.buffer << 8) | read_byte(); + rc.low = (rc.low << 8) | ((rc.buffer >> 1) & 0xff); + rc.range <<= 8; + } +} + +/* Calculate culmulative frequency for next symbol. Does NO update!*/ +/* tot_f is the total frequency */ +/* or: totf is (code_value)1<>shift; + tmp = rc.low/rc.help; + return tmp; +} + + +/* Update decoding state */ +/* sy_f is the interval length (frequency of the symbol) */ +/* lt_f is the lower end (frequency sum of < symbols) */ +static inline void range_decode_update(int sy_f, int lt_f) +{ int tmp; + tmp = rc.help * lt_f; + rc.low -= tmp; + rc.range = rc.help * sy_f; +} + + +/* Decode a byte/short without modelling */ +static inline unsigned char decode_byte(void) +{ int tmp = range_decode_culshift(8); + range_decode_update( 1,tmp); + return tmp; +} + +static inline int short range_decode_short(void) +{ int tmp = range_decode_culshift(16); + range_decode_update( 1,tmp); + return tmp; +} + +/* Decode n bits (n <= 16) without modelling - based on range_decode_short */ +static inline int range_decode_bits(int n) +{ int tmp = range_decode_culshift(n); + range_decode_update( 1,tmp); + return tmp; +} + + +/* Finish decoding */ +static inline void range_done_decoding(void) +{ range_dec_normalize(); /* normalize to use up all bytes */ +} diff --git a/apps/codecs/demac/libdemac/vector_math16.h b/apps/codecs/demac/libdemac/vector_math16.h new file mode 100644 index 0000000000..5d82abe930 --- /dev/null +++ b/apps/codecs/demac/libdemac/vector_math16.h @@ -0,0 +1,140 @@ +/* + +libdemac - A Monkey's Audio decoder + +$Id:$ + +Copyright (C) Dave Chapman 2007 + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA + +*/ + +static inline void vector_add(int16_t* v1, int16_t* v2) +{ +#if ORDER > 32 + int order = (ORDER >> 5); + while (order--) +#endif + { + *v1++ += *v2++; + *v1++ += *v2++; + *v1++ += *v2++; + *v1++ += *v2++; + *v1++ += *v2++; + *v1++ += *v2++; + *v1++ += *v2++; + *v1++ += *v2++; + *v1++ += *v2++; + *v1++ += *v2++; + *v1++ += *v2++; + *v1++ += *v2++; + *v1++ += *v2++; + *v1++ += *v2++; + *v1++ += *v2++; + *v1++ += *v2++; +#if ORDER > 16 + *v1++ += *v2++; + *v1++ += *v2++; + *v1++ += *v2++; + *v1++ += *v2++; + *v1++ += *v2++; + *v1++ += *v2++; + *v1++ += *v2++; + *v1++ += *v2++; + *v1++ += *v2++; + *v1++ += *v2++; + *v1++ += *v2++; + *v1++ += *v2++; + *v1++ += *v2++; + *v1++ += *v2++; + *v1++ += *v2++; + *v1++ += *v2++; +#endif + } +} + +static inline void vector_sub(int16_t* v1, int16_t* v2) +{ +#if ORDER > 32 + int order = (ORDER >> 5); + while (order--) +#endif + { + *v1++ -= *v2++; + *v1++ -= *v2++; + *v1++ -= *v2++; + *v1++ -= *v2++; + *v1++ -= *v2++; + *v1++ -= *v2++; + *v1++ -= *v2++; + *v1++ -= *v2++; + *v1++ -= *v2++; + *v1++ -= *v2++; + *v1++ -= *v2++; + *v1++ -= *v2++; + *v1++ -= *v2++; + *v1++ -= *v2++; + *v1++ -= *v2++; + *v1++ -= *v2++; +#if ORDER > 16 + *v1++ -= *v2++; + *v1++ -= *v2++; + *v1++ -= *v2++; + *v1++ -= *v2++; + *v1++ -= *v2++; + *v1++ -= *v2++; + *v1++ -= *v2++; + *v1++ -= *v2++; + *v1++ -= *v2++; + *v1++ -= *v2++; + *v1++ -= *v2++; + *v1++ -= *v2++; + *v1++ -= *v2++; + *v1++ -= *v2++; + *v1++ -= *v2++; + *v1++ -= *v2++; +#endif + } +} + +static inline int32_t scalarproduct(int16_t* v1, int16_t* v2) +{ + int res = 0; + +#if ORDER > 16 + int order = (ORDER >> 4); + while (order--) +#endif + { + res += *v1++ * *v2++; + res += *v1++ * *v2++; + res += *v1++ * *v2++; + res += *v1++ * *v2++; + res += *v1++ * *v2++; + res += *v1++ * *v2++; + res += *v1++ * *v2++; + res += *v1++ * *v2++; + res += *v1++ * *v2++; + res += *v1++ * *v2++; + res += *v1++ * *v2++; + res += *v1++ * *v2++; + res += *v1++ * *v2++; + res += *v1++ * *v2++; + res += *v1++ * *v2++; + res += *v1++ * *v2++; + } + return res; +} diff --git a/apps/codecs/demac/libdemac/vector_math32.h b/apps/codecs/demac/libdemac/vector_math32.h new file mode 100644 index 0000000000..b32867ca5d --- /dev/null +++ b/apps/codecs/demac/libdemac/vector_math32.h @@ -0,0 +1,54 @@ +/* + +libdemac - A Monkey's Audio decoder + +$Id:$ + +Copyright (C) Dave Chapman 2007 + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA + +*/ + +/* 32-bit vector math functions */ + +#define scalarproduct4_rev32(x,y) ((x[0] * y[0]) + (x[1] * y[-1]) + \ + (x[2] * y[-2]) + (x[3] * y[-3])) + +#define scalarproduct5_rev32(x,y) ((x[0] * y[0]) + (x[1] * y[-1]) + \ + (x[2] * y[-2]) + (x[3] * y[-3]) + \ + (x[4] * y[-4])) + +#define vector_sub4_rev32(x, y) { x[0] -= y[0]; \ + x[1] -= y[-1]; \ + x[2] -= y[-2]; \ + x[3] -= y[-3]; } + +#define vector_sub5_rev32(x, y) { x[0] -= y[0]; \ + x[1] -= y[-1]; \ + x[2] -= y[-2]; \ + x[3] -= y[-3]; \ + x[4] -= y[-4]; } + +#define vector_add4_rev32(x, y) { x[0] += y[0]; \ + x[1] += y[-1]; \ + x[2] += y[-2]; \ + x[3] += y[-3]; } + +#define vector_add5_rev32(x, y) { x[0] += y[0]; \ + x[1] += y[-1]; \ + x[2] += y[-2]; \ + x[3] += y[-3]; \ + x[4] += y[-4]; } diff --git a/apps/codecs/demac/wavwrite.c b/apps/codecs/demac/wavwrite.c new file mode 100644 index 0000000000..5fb82e148a --- /dev/null +++ b/apps/codecs/demac/wavwrite.c @@ -0,0 +1,107 @@ +/* + +demac - A Monkey's Audio decoder + +$Id:$ + +Copyright (C) Dave Chapman 2007 + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "parser.h" + + +static unsigned char wav_header[44]={ + 'R','I','F','F',// 0 - ChunkID + 0,0,0,0, // 4 - ChunkSize (filesize-8) + 'W','A','V','E',// 8 - Format + 'f','m','t',' ',// 12 - SubChunkID + 16,0,0,0, // 16 - SubChunk1ID // 16 for PCM + 1,0, // 20 - AudioFormat (1=Uncompressed) + 2,0, // 22 - NumChannels + 0,0,0,0, // 24 - SampleRate in Hz + 0,0,0,0, // 28 - Byte Rate (SampleRate*NumChannels*(BitsPerSample/8) + 4,0, // 32 - BlockAlign (== NumChannels * BitsPerSample/8) + 16,0, // 34 - BitsPerSample + 'd','a','t','a',// 36 - Subchunk2ID + 0,0,0,0 // 40 - Subchunk2Size +}; + +int open_wav(struct ape_ctx_t* ape_ctx, char* filename) +{ + int fd; + int x; + int filesize; + int bytespersample; + + fd=creat(filename,0644); + if (fd < 0) + return fd; + + bytespersample=ape_ctx->bps/8; + + filesize=ape_ctx->totalsamples*bytespersample*ape_ctx->channels+44; + + // ChunkSize + x=filesize-8; + wav_header[4]=(x&0xff); + wav_header[5]=(x&0xff00)>>8; + wav_header[6]=(x&0xff0000)>>16; + wav_header[7]=(x&0xff000000)>>24; + + // Number of channels + wav_header[22]=ape_ctx->channels; + + // Samplerate + wav_header[24]=ape_ctx->samplerate&0xff; + wav_header[25]=(ape_ctx->samplerate&0xff00)>>8; + wav_header[26]=(ape_ctx->samplerate&0xff0000)>>16; + wav_header[27]=(ape_ctx->samplerate&0xff000000)>>24; + + // ByteRate + x=ape_ctx->samplerate*(ape_ctx->bps/8)*ape_ctx->channels; + wav_header[28]=(x&0xff); + wav_header[29]=(x&0xff00)>>8; + wav_header[30]=(x&0xff0000)>>16; + wav_header[31]=(x&0xff000000)>>24; + + // BlockAlign + wav_header[32]=(ape_ctx->bps/8)*ape_ctx->channels; + + // Bits per sample + wav_header[34]=ape_ctx->bps; + + // Subchunk2Size + x=filesize-44; + wav_header[40]=(x&0xff); + wav_header[41]=(x&0xff00)>>8; + wav_header[42]=(x&0xff0000)>>16; + wav_header[43]=(x&0xff000000)>>24; + + write(fd,wav_header,sizeof(wav_header)); + + return fd; +} diff --git a/apps/codecs/demac/wavwrite.h b/apps/codecs/demac/wavwrite.h new file mode 100644 index 0000000000..eba8ac7e31 --- /dev/null +++ b/apps/codecs/demac/wavwrite.h @@ -0,0 +1,32 @@ +/* + +demac - A Monkey's Audio decoder + +$Id:$ + +Copyright (C) Dave Chapman 2007 + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA + +*/ + +#ifndef _APE_WAVWRITE_H +#define _APE_WAVWRITE_H + +#include "parser.h" + +int open_wav(struct ape_ctx_t* ape_ctx, char* filename); + +#endif diff --git a/apps/filetypes.c b/apps/filetypes.c index 3e03c0bda1..e826efc7dc 100644 --- a/apps/filetypes.c +++ b/apps/filetypes.c @@ -76,6 +76,8 @@ const struct filetype inbuilt_filetypes[] = { { "nsf", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA }, { "nsfe",FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA }, { "spc", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA }, + { "ape", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA }, + { "mac", FILE_ATTR_AUDIO, Icon_Audio, VOICE_EXT_MPA }, #endif { "m3u", FILE_ATTR_M3U, Icon_Playlist, LANG_PLAYLIST }, { "m3u8",FILE_ATTR_M3U, Icon_Playlist, LANG_PLAYLIST }, diff --git a/apps/metadata.c b/apps/metadata.c index 1bbff1d370..60191b1eb8 100644 --- a/apps/metadata.c +++ b/apps/metadata.c @@ -982,6 +982,56 @@ static bool get_flac_metadata(int fd, struct mp3entry* id3) return true; } +static bool get_monkeys_metadata(int fd, struct mp3entry* id3) +{ + /* Use the trackname part of the id3 structure as a temporary buffer */ + unsigned char* buf = (unsigned char *)id3->path; + unsigned char* header; + bool rc = false; + uint32_t descriptorlength; + uint32_t totalsamples; + uint32_t blocksperframe, finalframeblocks, totalframes; + + lseek(fd, 0, SEEK_SET); + + if (read(fd, buf, 4) < 4) + { + return rc; + } + + if (memcmp(buf, "MAC ", 4) != 0) + { + return rc; + } + + read(fd, buf + 4, MAX_PATH - 4); + + descriptorlength = buf[8] | (buf[9] << 8) | + (buf[10] << 16) | (buf[11] << 24); + + header = buf + descriptorlength; + + blocksperframe = header[4] | (header[5] << 8) | + (header[6] << 16) | (header[7] << 24); + finalframeblocks = header[8] | (header[9] << 8) | + (header[10] << 16) | (header[11] << 24); + totalframes = header[12] | (header[13] << 8) | + (header[14] << 16) | (header[15] << 24); + + id3->vbr = true; /* All FLAC files are VBR */ + id3->filesize = filesize(fd); + id3->frequency = header[20] | (header[21] << 8) | + (header[22] << 16) | (header[23] << 24); + + totalsamples = finalframeblocks; + if (totalframes > 1) + totalsamples += blocksperframe * (totalframes-1); + + id3->length = ((int64_t) totalsamples * 1000) / id3->frequency; + id3->bitrate = (id3->filesize * 8) / id3->length; + return true; +} + static bool get_wave_metadata(int fd, struct mp3entry* id3) { /* Use the trackname part of the id3 structure as a temporary buffer */ @@ -2152,6 +2202,14 @@ bool get_metadata(struct track_info* track, int fd, const char* trackname, break; + case AFMT_APE: + if (!get_monkeys_metadata(fd, &(track->id3))) + { + return false; + } + read_ape_tags(fd, &(track->id3)); + break; + case AFMT_MPC: if (!get_musepack_metadata(fd, &(track->id3))) return false; diff --git a/firmware/export/id3.h b/firmware/export/id3.h index 5cc600face..791f86390e 100644 --- a/firmware/export/id3.h +++ b/firmware/export/id3.h @@ -53,6 +53,7 @@ enum AFMT_NSF, /* NESM (NES Sound Format) */ AFMT_SPEEX, /* Ogg Speex speech */ AFMT_SPC, /* SPC700 save state */ + AFMT_APE, /* Monkey's Audio (APE) */ #endif /* add new formats at any index above this line to have a sensible order - diff --git a/firmware/id3.c b/firmware/id3.c index eaaf2a9ecd..3e7b392554 100644 --- a/firmware/id3.c +++ b/firmware/id3.c @@ -107,6 +107,9 @@ const struct afmt_entry audio_formats[AFMT_NUM_CODECS] = /* SPC700 Save State */ [AFMT_SPC] = AFMT_ENTRY("SPC", "spc", NULL, "spc\0" ), + /* APE (Monkey's Audio) */ + [AFMT_APE] = + AFMT_ENTRY("APE", "ape", NULL, "ape\0mac\0" ), #endif }; diff --git a/tools/configure b/tools/configure index 1f041f7ebf..1a84a487ee 100755 --- a/tools/configure +++ b/tools/configure @@ -756,7 +756,7 @@ EOF archosrom="" flash="$pwd/rombox.iriver" plugins="yes" - codecs="libmad liba52 libffmpegFLAC libTremor libwavpack libmusepack libalac libfaad libm4a libspeex" + codecs="libmad liba52 libffmpegFLAC libTremor libwavpack libmusepack libalac libfaad libm4a libspeex libdemac" # toolset is the tools within the tools directory that we build for # this particular target. toolset=$iriverbitmaptools @@ -781,7 +781,7 @@ EOF archosrom="" flash="" plugins="yes" - codecs="libmad liba52 libffmpegFLAC libTremor libwavpack libmusepack libalac libfaad libm4a libspeex" + codecs="libmad liba52 libffmpegFLAC libTremor libwavpack libmusepack libalac libfaad libm4a libspeex libdemac" # toolset is the tools within the tools directory that we build for # this particular target. toolset=$iriverbitmaptools @@ -806,7 +806,7 @@ EOF archosrom="" flash="" plugins="yes" - codecs="libmad liba52 libffmpegFLAC libTremor libwavpack libmusepack libalac libfaad libm4a libspeex" + codecs="libmad liba52 libffmpegFLAC libTremor libwavpack libmusepack libalac libfaad libm4a libspeex libdemac" # toolset is the tools within the tools directory that we build for # this particular target. toolset=$iriverbitmaptools @@ -831,7 +831,7 @@ EOF archosrom="" flash="" plugins="yes" - codecs="libmad liba52 libffmpegFLAC libTremor libwavpack libmusepack libalac libfaad libm4a libspeex" + codecs="libmad liba52 libffmpegFLAC libTremor libwavpack libmusepack libalac libfaad libm4a libspeex libdemac" # toolset is the tools within the tools directory that we build for # this particular target. toolset="$iaudiobitmaptools" @@ -857,7 +857,7 @@ EOF archosrom="" flash="" plugins="yes" - codecs="libmad liba52 libffmpegFLAC libTremor libwavpack libmusepack libalac libfaad libm4a libspeex" + codecs="libmad liba52 libffmpegFLAC libTremor libwavpack libmusepack libalac libfaad libm4a libspeex libdemac" # toolset is the tools within the tools directory that we build for # this particular target. toolset="$iaudiobitmaptools" @@ -881,7 +881,7 @@ EOF archosrom="" flash="" plugins="yes" - codecs="libmad liba52 libffmpegFLAC libTremor libwavpack libmusepack libalac libfaad libm4a libspeex" + codecs="libmad liba52 libffmpegFLAC libTremor libwavpack libmusepack libalac libfaad libm4a libspeex libdemac" bootoutput="bootloader-$archos.ipod" # toolset is the tools within the tools directory that we build for # this particular target. @@ -906,7 +906,7 @@ EOF archosrom="" flash="" plugins="yes" - codecs="libmad liba52 libffmpegFLAC libTremor libwavpack libmusepack libalac libfaad libm4a libspeex" + codecs="libmad liba52 libffmpegFLAC libTremor libwavpack libmusepack libalac libfaad libm4a libspeex libdemac" bootoutput="bootloader-$archos.ipod" # toolset is the tools within the tools directory that we build for # this particular target. @@ -930,7 +930,7 @@ EOF archosrom="" flash="" plugins="yes" - codecs="libmad liba52 libffmpegFLAC libTremor libwavpack libmusepack libalac libfaad libm4a libspeex" + codecs="libmad liba52 libffmpegFLAC libTremor libwavpack libmusepack libalac libfaad libm4a libspeex libdemac" bootoutput="bootloader-$archos.ipod" # toolset is the tools within the tools directory that we build for # this particular target. @@ -955,7 +955,7 @@ EOF archosrom="" flash="" plugins="yes" - codecs="libmad liba52 libffmpegFLAC libTremor libwavpack libmusepack libalac libfaad libm4a libspeex" + codecs="libmad liba52 libffmpegFLAC libTremor libwavpack libmusepack libalac libfaad libm4a libspeex libdemac" bootoutput="bootloader-$archos.ipod" # toolset is the tools within the tools directory that we build for # this particular target. @@ -980,7 +980,7 @@ EOF archosrom="" flash="" plugins="yes" - codecs="libmad liba52 libffmpegFLAC libTremor libwavpack libmusepack libalac libfaad libm4a libspeex" + codecs="libmad liba52 libffmpegFLAC libTremor libwavpack libmusepack libalac libfaad libm4a libspeex libdemac" bootoutput="bootloader-$archos.ipod" # toolset is the tools within the tools directory that we build for # this particular target. @@ -1005,7 +1005,7 @@ EOF archosrom="" flash="" plugins="yes" - codecs="libmad liba52 libffmpegFLAC libTremor libwavpack libmusepack libalac libfaad libm4a libspeex" + codecs="libmad liba52 libffmpegFLAC libTremor libwavpack libmusepack libalac libfaad libm4a libspeex libdemac" bootoutput="bootloader-$archos.ipod" # toolset is the tools within the tools directory that we build for # this particular target. @@ -1030,7 +1030,7 @@ EOF archosrom="" flash="" plugins="yes" - codecs="libmad liba52 libffmpegFLAC libTremor libwavpack libmusepack libalac libfaad libm4a libspeex" + codecs="libmad liba52 libffmpegFLAC libTremor libwavpack libmusepack libalac libfaad libm4a libspeex libdemac" # toolset is the tools within the tools directory that we build for # this particular target. toolset=$genericbitmaptools @@ -1053,7 +1053,7 @@ EOF archosrom="" flash="" plugins="yes" - codecs="libmad liba52 libffmpegFLAC libTremor libwavpack libmusepack libalac libfaad libm4a libspeex" + codecs="libmad liba52 libffmpegFLAC libTremor libwavpack libmusepack libalac libfaad libm4a libspeex libdemac" toolset=$gigabeatbitmaptools boottool="$rootdir/tools/scramble -gigabeat" bootoutput="FWIMG01.DAT" @@ -1077,7 +1077,7 @@ EOF archosrom="" flash="" plugins="yes" - codecs="libmad liba52 libffmpegFLAC libTremor libwavpack libmusepack libalac libfaad libm4a libspeex" + codecs="libmad liba52 libffmpegFLAC libTremor libwavpack libmusepack libalac libfaad libm4a libspeex libdemac" bootoutput="bootloader-$archos.ipod" # toolset is the tools within the tools directory that we build for # this particular target. @@ -1102,7 +1102,7 @@ EOF archosrom="" flash="" plugins="yes" - codecs="libmad liba52 libffmpegFLAC libTremor libwavpack libmusepack libalac libfaad libm4a libspeex" + codecs="libmad liba52 libffmpegFLAC libTremor libwavpack libmusepack libalac libfaad libm4a libspeex libdemac" boottool="$rootdir/tools/scramble -mi4v3 -model=h10 -type=RBBL" bootoutput="H10_20GC.mi4" # toolset is the tools within the tools directory that we build for @@ -1128,7 +1128,7 @@ EOF archosrom="" flash="" plugins="yes" - codecs="libmad liba52 libffmpegFLAC libTremor libwavpack libmusepack libalac libfaad libm4a libspeex" + codecs="libmad liba52 libffmpegFLAC libTremor libwavpack libmusepack libalac libfaad libm4a libspeex libdemac" boottool="$rootdir/tools/scramble -mi4v2 -model=h105 -type=RBBL" bootoutput="H10.mi4" # toolset is the tools within the tools directory that we build for @@ -1154,7 +1154,7 @@ EOF archosrom="" flash="" plugins="yes" - codecs="libmad liba52 libffmpegFLAC libTremor libwavpack libmusepack libalac libfaad libm4a libspeex" + codecs="libmad liba52 libffmpegFLAC libTremor libwavpack libmusepack libalac libfaad libm4a libspeex libdemac" boottool="$rootdir/tools/scramble -mi4v3 -model=e200 -type=RBBL" bootoutput="PP5022.mi4" # toolset is the tools within the tools directory that we build for @@ -1183,7 +1183,7 @@ EOF archosrom="" flash="" plugins="yes" - codecs="libmad liba52 libffmpegFLAC libTremor libwavpack libmusepack libalac libfaad libm4a libspeex" + codecs="libmad liba52 libffmpegFLAC libTremor libwavpack libmusepack libalac libfaad libm4a libspeex libdemac" boottool="$rootdir/tools/scramble -mi4r -model=e20r -type=RBBL" bootoutput="pp5022.mi4" # toolset is the tools within the tools directory that we build for @@ -1209,7 +1209,7 @@ EOF archosrom="" flash="" plugins="yes" - codecs="libmad liba52 libffmpegFLAC libTremor libwavpack libmusepack libalac libfaad libm4a libspeex" + codecs="libmad liba52 libffmpegFLAC libTremor libwavpack libmusepack libalac libfaad libm4a libspeex libdemac" boottool="$rootdir/tools/scramble -mi4v2" bootoutput="pp5020.mi4" # toolset is the tools within the tools directory that we build for -- cgit v1.2.3