diff --git a/CMakeLists.txt b/CMakeLists.txt index 9a583f59..9f942078 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -51,10 +51,7 @@ option(USE_MAIATRAC3PLUS "Use MAIATRAC3+ for support of ATRAC3+" OFF) option(USE_G7221 "Use G7221 for support of ITU-T G.722.1 annex C" ON) option(USE_G719 "Use libg719_decode for support ITU-T G.719" ON) option(USE_ATRAC9 "Use LibAtrac9 for support of ATRAC9" ON) -if(WIN32) - # May need to see if it is possible to get these to work on non-Windows systems too - option(USE_CELT "Use libcelt for support of FSB CELT versions 0.6.1 and 0.11.0" ON) -endif() +option(USE_CELT "Use libcelt for support of FSB CELT versions 0.6.1 and 0.11.0" ON) option(USE_SPEEX "Use libspeex for support of SPEEX" ON) if(NOT WIN32) option(USE_JANSSON "Use jansson for JSON dumping" ON) @@ -69,6 +66,8 @@ if(NOT WIN32) set(G719_PATH CACHE PATH "Path to G.719 decoder") set(ATRAC9_PATH CACHE PATH "Path to LibAtrac9") set(SPEEX_PATH CACHE PATH "Path to SPEEX") + set(CELT0061_PATH CACHE PATH "Path to CELT version 0.6.1") + set(CELT0110_PATH CACHE PATH "Path to CELT version 0.11.0") set(LIBAO_PATH CACHE PATH "Path to libao") endif() @@ -144,11 +143,13 @@ include(FetchDependency) include(dependencies/ffmpeg) include(dependencies/mpg123) +include(dependencies/ogg) include(dependencies/vorbis) include(dependencies/libao) include(dependencies/maitrac3plus) include(dependencies/g719) include(dependencies/atrac9) +include(dependencies/celt) include(dependencies/speex) include(dependencies/jansson) include(dependencies/audacious) @@ -262,9 +263,7 @@ message(STATUS " MAIATRAC3+: ${USE_MAIATRAC3PLUS} ${MAIATRAC3PLUS_SOURCE}") message(STATUS " G.722.1: ${USE_G7221} ${G7221_SOURCE}") message(STATUS " G.719: ${USE_G719} ${G719_SOURCE}") message(STATUS " ATRAC9: ${USE_ATRAC9} ${ATRAC9_SOURCE}") -if(WIN32) - message(STATUS " FSB CELT: ${USE_CELT}") -endif() +message(STATUS " FSB CELT: ${USE_CELT} ${CELT_SOURCE}") message(STATUS " SPEEX: ${USE_SPEEX} ${SPEEX_SOURCE}") if(NOT WIN32) message(STATUS " LIBAO: ${BUILD_V123} ${LIBAO_SOURCE}") diff --git a/cmake/dependencies/celt.cmake b/cmake/dependencies/celt.cmake new file mode 100644 index 00000000..012d8d77 --- /dev/null +++ b/cmake/dependencies/celt.cmake @@ -0,0 +1,165 @@ +if(NOT WIN32 AND USE_CELT) + FetchDependency(CELT_0061 + DIR celt-0061 + FETCH_PRIORITY file git + + FILE_DOWNLOAD https://downloads.xiph.org/releases/celt/celt-0.6.1.tar.gz + FILE_SUBDIR celt-0.6.1 + + GIT_REPOSITORY https://gitlab.xiph.org/xiph/celt + GIT_TAG 8ccf148573277b983692e15d5f0753081f806bea + ) + FetchDependency(CELT_0110 + DIR celt-0110 + FETCH_PRIORITY file git + + FILE_DOWNLOAD https://downloads.xiph.org/releases/celt/celt-0.11.0.tar.gz + FILE_SUBDIR celt-0.11.0 + + GIT_REPOSITORY https://gitlab.xiph.org/xiph/celt + GIT_TAG 0b405d1170122c859faab435405666506d52fa2e + ) + if(CELT_0061_PATH AND CELT_0110_PATH) + set(CELT_0061_LINK_PATH ${CELT_0061_BIN}/libcelt/.libs/libcelt.a) + set(CELT_0110_LINK_PATH ${CELT_0110_BIN}/libcelt/.libs/libcelt0.a) + + configure_file( + ${VGM_SOURCE_DIR}/ext_libs/celt-0110/ecintrin.h + ${CELT_0110_PATH}/libcelt/ecintrin.h + COPYONLY) + + set(CELT_CFLAGS + alg_quant + alg_unquant + celt_decode + celt_decoder_create + celt_decoder_create_custom + celt_decoder_destroy + celt_mode_create + celt_mode_destroy + celt_mode_info + celt_encoder_destroy + celt_encoder_create + celt_encode + celt_encode_float + celt_encoder_ctl + celt_decode_float + celt_decoder_ctl + compute_allocation + compute_band_energies + denormalise_bands + ec_dec_init + ec_decode + ec_decode_bin + ec_dec_update + ec_dec_uint + ec_dec_bits + ec_enc_init + ec_encode + ec_encode_bin + ec_enc_uint + ec_enc_bits + ec_enc_done + normalise_bands + renormalise_vector + quant_coarse_energy + quant_fine_energy + quant_energy_finalise + unquant_coarse_energy + unquant_energy_finalise + unquant_fine_energy + eMeans + encode_pulses + decode_pulses + ec_laplace_encode + ec_laplace_decode + celt_decoder_get_size + celt_decoder_init + ec_dec_bit_logp + ec_dec_icdf + ec_enc_bit_logp + ec_enc_icdf + ec_enc_shrink + _celt_lpc + _celt_autocorr + amp2Log2 + stereo_itheta + anti_collapse + spreading_decision + haar1 + quant_all_bands + log2_frac + icwrs + get_required_bits + ec_ilog + mdct_forward + mdct_backward + mdct_init + mdct_clear + ) + + foreach(ver 0061 0110) + foreach(source ${CELT_CFLAGS}) + string(REGEX REPLACE "^([^_]+)" "\\1_${ver}" target ${source}) + if(source STREQUAL ${target}) + set(target "${source}_${ver}") + endif() + list(APPEND CELT_${ver}_CFLAGS "-D${source}=${target}") + endforeach() + list(APPEND CELT_${ver}_CFLAGS "-fPIC") + + set(CELT_${ver}_CONF + --enable-static + --disable-shared + --disable-oggtest + CC="${CMAKE_C_COMPILER}" + AR="${CMAKE_AR}" + CFLAGS="${CELT_${ver}_CFLAGS}" + ) + if(ver STREQUAL "0110") + list(APPEND CELT_${ver}_CONF --enable-custom-modes) + endif() + + if(NOT EXISTS ${CELT_${ver}_PATH}/configure) + add_custom_target(CELT_${ver}_AUTOGEN + COMMAND ./autogen.sh + BYPRODUCTS ${CELT_${ver}_PATH}/configure + WORKING_DIRECTORY ${CELT_${ver}_PATH} + ) + endif() + + file(MAKE_DIRECTORY ${CELT_${ver}_BIN}) + add_custom_target(CELT_${ver}_CONFIGURE + COMMAND "${CELT_${ver}_PATH}/configure" ${CELT_${ver}_CONF} + DEPENDS ${CELT_${ver}_PATH}/configure + BYPRODUCTS ${CELT_${ver}_BIN}/Makefile + WORKING_DIRECTORY ${CELT_${ver}_BIN} + ) + add_custom_target(CELT_${ver}_MAKE + COMMAND make SUBDIRS=libcelt DIST_SUBDIRS=libcelt + DEPENDS ${CELT_${ver}_BIN}/Makefile + BYPRODUCTS ${CELT_${ver}_LINK_PATH} ${CELT_${ver}_BIN} + WORKING_DIRECTORY ${CELT_${ver}_BIN} + ) + + add_library(celt${ver} STATIC IMPORTED) + if(NOT EXISTS ${CELT_${ver}_LINK_PATH}) + add_dependencies(celt${ver} CELT_${ver}_MAKE) + endif() + set_target_properties(celt${ver} PROPERTIES + IMPORTED_LOCATION ${CELT_${ver}_LINK_PATH} + ) + endforeach() + else() + set(USE_CELT OFF) + endif() +endif() +if(USE_CELT) + if(CELT_0061_SOURCE STREQUAL "${CELT_0110_SOURCE}") + set(CELT_SOURCE ${CELT_0061_SOURCE}) + else() + set(CELT_SOURCE "v0.6.1: ${CELT_0061_SOURCE}, v0.11.0: ${CELT_0110_SOURCE}") + endif() +else() + unset(CELT_SOURCE) +endif() diff --git a/cmake/dependencies/g719.cmake b/cmake/dependencies/g719.cmake index c24a6151..6df599d5 100644 --- a/cmake/dependencies/g719.cmake +++ b/cmake/dependencies/g719.cmake @@ -10,7 +10,7 @@ if(NOT WIN32 AND USE_G719) ${VGM_SOURCE_DIR}/ext_libs/libg719_decode/CMakeLists.txt ${G719_PATH}/CMakeLists.txt COPYONLY) - add_subdirectory(${G719_PATH} ${G719_BIN}) + add_subdirectory(${G719_PATH} ${G719_BIN} EXCLUDE_FROM_ALL) endif() endif() if(NOT USE_G719) diff --git a/cmake/dependencies/maitrac3plus.cmake b/cmake/dependencies/maitrac3plus.cmake index 42eb6fce..a5aeb046 100644 --- a/cmake/dependencies/maitrac3plus.cmake +++ b/cmake/dependencies/maitrac3plus.cmake @@ -16,7 +16,7 @@ if(USE_MAIATRAC3PLUS) ${MAIATRAC3PLUS_PATH}/MaiAT3PlusDecoder/src/base/Mai_mem.cc ${MAIATRAC3PLUS_PATH}/MaiAT3PlusDecoder/src/base/Mai_Mem.cc COPYONLY) - add_subdirectory(${MAIATRAC3PLUS_PATH}/MaiAT3PlusDecoder ${MAIATRAC3PLUS_BIN}) + add_subdirectory(${MAIATRAC3PLUS_PATH}/MaiAT3PlusDecoder ${MAIATRAC3PLUS_BIN} EXCLUDE_FROM_ALL) else() message(FATAL_ERROR "Path to MAIATRAC3+ must be set. (Use MAIATRAC3PLUS_PATH)") endif() diff --git a/cmake/dependencies/ogg.cmake b/cmake/dependencies/ogg.cmake new file mode 100644 index 00000000..b3d3074c --- /dev/null +++ b/cmake/dependencies/ogg.cmake @@ -0,0 +1,25 @@ +if(NOT WIN32 AND USE_VORBIS) + if(NOT OGG_PATH) + find_package(Ogg QUIET) + + if(OGG_FOUND) + set(OGG_SOURCE "(system)") + endif() + endif() + if(OGG_PATH OR NOT OGG_FOUND) + FetchDependency(OGG + DIR ogg + GIT_REPOSITORY https://gitlab.xiph.org/xiph/ogg + GIT_TAG v1.3.5 + ) + + if(OGG_PATH) + add_subdirectory(${OGG_PATH} ${OGG_BIN} EXCLUDE_FROM_ALL) + set(OGG_INCLUDE_DIR ${OGG_PATH}/include ${OGG_BIN}/include) + set(OGG_LIBRARY ogg) + endif() + endif() +endif() +if(NOT OGG_PATH) + unset(OGG_SOURCE) +endif() diff --git a/cmake/dependencies/speex.cmake b/cmake/dependencies/speex.cmake index 8061ec1f..73b6dba9 100644 --- a/cmake/dependencies/speex.cmake +++ b/cmake/dependencies/speex.cmake @@ -26,7 +26,7 @@ if(NOT WIN32 AND USE_SPEEX) file(MAKE_DIRECTORY ${SPEEX_BIN}) add_custom_target(SPEEX_CONFIGURE - COMMAND "${SPEEX_PATH}/configure" --enable-static --disable-shared --disable-binaries CC="${CMAKE_C_COMPILER}" AR="${CMAKE_AR}" + COMMAND "${SPEEX_PATH}/configure" --enable-static --disable-shared --disable-binaries CC="${CMAKE_C_COMPILER}" AR="${CMAKE_AR}" RANLIB="${CMAKE_RANLIB}" DEPENDS ${SPEEX_PATH}/configure BYPRODUCTS ${SPEEX_BIN}/Makefile WORKING_DIRECTORY ${SPEEX_BIN} diff --git a/cmake/dependencies/vorbis.cmake b/cmake/dependencies/vorbis.cmake index 85f4b77b..23857a14 100644 --- a/cmake/dependencies/vorbis.cmake +++ b/cmake/dependencies/vorbis.cmake @@ -1,29 +1,20 @@ if(NOT WIN32 AND USE_VORBIS) - if(NOT VORBIS_PATH OR NOT OGG_PATH) + if(NOT VORBIS_PATH) find_package(VorbisFile QUIET) if(VORBISFILE_FOUND) set(VORBIS_SOURCE "(system)") endif() endif() - if(VORBIS_PATH AND OGG_PATH OR NOT VORBISFILE_FOUND) - FetchDependency(OGG - DIR ogg - GIT_REPOSITORY https://gitlab.xiph.org/xiph/ogg - GIT_TAG v1.3.5 - ) + if(VORBIS_PATH AND (OGG_PATH OR OGG_FOUND) OR NOT VORBISFILE_FOUND) FetchDependency(VORBIS DIR vorbis GIT_REPOSITORY https://gitlab.xiph.org/xiph/vorbis GIT_TAG v1.3.7 ) - if(OGG_PATH AND VORBIS_PATH) - add_subdirectory(${OGG_PATH} ${OGG_BIN}) - set(OGG_INCLUDE_DIR ${OGG_PATH}/include ${OGG_BIN}/include) - set(OGG_LIBRARY ogg) - - add_subdirectory(${VORBIS_PATH} ${VORBIS_BIN}) + if(VORBIS_PATH) + add_subdirectory(${VORBIS_PATH} ${VORBIS_BIN} EXCLUDE_FROM_ALL) set(OGG_VORBIS_INCLUDE_DIR ${VORBIS_PATH}/include) set(OGG_VORBIS_LIBRARY vorbis) diff --git a/cmake/vgmstream.cmake b/cmake/vgmstream.cmake index a819c876..b149696c 100644 --- a/cmake/vgmstream.cmake +++ b/cmake/vgmstream.cmake @@ -121,12 +121,15 @@ macro(setup_target TARGET) if(USE_CELT) target_compile_definitions(${TARGET} PRIVATE VGM_USE_CELT) - if(LINK) + if(WIN32 AND LINK) add_dependencies(${TARGET} libcelt) target_link_libraries(${TARGET} ${VGM_BINARY_DIR}/ext_libs/libcelt-0061.lib ${VGM_BINARY_DIR}/ext_libs/libcelt-0110.lib) endif() + if(NOT WIN32 AND LINK) + target_link_libraries(${TARGET} celt0061 celt0110 m) + endif() endif() if(USE_SPEEX) diff --git a/ext_libs/celt-0110/ecintrin.h b/ext_libs/celt-0110/ecintrin.h new file mode 100644 index 00000000..0348e6d7 --- /dev/null +++ b/ext_libs/celt-0110/ecintrin.h @@ -0,0 +1,140 @@ +/* Copyright (c) 2003-2008 Timothy B. Terriberry + Copyright (c) 2008 Xiph.Org Foundation */ +/* + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + - Neither the name of the Xiph.org Foundation nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/*Some common macros for potential platform-specific optimization.*/ +#include +#include +#if !defined(_ecintrin_H) +# define _ecintrin_H (1) + +/*Some specific platforms may have optimized intrinsic or inline assembly + versions of these functions which can substantially improve performance. + We define macros for them to allow easy incorporation of these non-ANSI + features.*/ + +/*Note that we do not provide a macro for abs(), because it is provided as a + library function, which we assume is translated into an intrinsic to avoid + the function call overhead and then implemented in the smartest way for the + target platform. + With modern gcc (4.x), this is true: it uses cmov instructions if the + architecture supports it and branchless bit-twiddling if it does not (the + speed difference between the two approaches is not measurable). + Interestingly, the bit-twiddling method was patented in 2000 (US 6,073,150) + by Sun Microsystems, despite prior art dating back to at least 1996: + http://web.archive.org/web/19961201174141/www.x86.org/ftp/articles/pentopt/PENTOPT.TXT + On gcc 3.x, however, our assumption is not true, as abs() is translated to a + conditional jump, which is horrible on deeply piplined architectures (e.g., + all consumer architectures for the past decade or more) when the sign cannot + be reliably predicted.*/ + +/*Modern gcc (4.x) can compile the naive versions of min and max with cmov if + given an appropriate architecture, but the branchless bit-twiddling versions + are just as fast, and do not require any special target architecture. + Earlier gcc versions (3.x) compiled both code to the same assembly + instructions, because of the way they represented ((_b)>(_a)) internally.*/ +#define EC_MAXI(_a,_b) ((_a)-((_a)-(_b)&-((_b)>(_a)))) +#define EC_MINI(_a,_b) ((_a)+((_b)-(_a)&-((_b)<(_a)))) +/*This has a chance of compiling branchless, and is just as fast as the + bit-twiddling method, which is slightly less portable, since it relies on a + sign-extended rightshift, which is not guaranteed by ANSI (but present on + every relevant platform).*/ +#define EC_SIGNI(_a) (((_a)>0)-((_a)<0)) +/*Slightly more portable than relying on a sign-extended right-shift (which is + not guaranteed by ANSI), and just as fast, since gcc (3.x and 4.x both) + compile it into the right-shift anyway.*/ +#define EC_SIGNMASK(_a) (-((_a)<0)) +/*Clamps an integer into the given range. + If _a>_c, then the lower bound _a is respected over the upper bound _c (this + behavior is required to meet our documented API behavior). + _a: The lower bound. + _b: The value to clamp. + _c: The upper boud.*/ +#define EC_CLAMPI(_a,_b,_c) (EC_MAXI(_a,EC_MINI(_b,_c))) + + +/*Count leading zeros. + This macro should only be used for implementing ec_ilog(), if it is defined. + All other code should use EC_ILOG() instead.*/ +#if defined(_MSC_VER) +# include +static __inline int ec_bsr(unsigned long _x){ + unsigned long ret; + _BitScanReverse(&ret,_x); + return (int)ret; +} +# define EC_CLZ0 (1) +# define EC_CLZ(_x) (-ec_bsr(_x)) +#elif defined(ENABLE_TI_DSPLIB) +# include "dsplib.h" +# define EC_CLZ0 (31) +# define EC_CLZ(_x) (_lnorm(x)) +#elif defined(__GNUC_PREREQ) +# if __GNUC_PREREQ(3,4) +# if INT_MAX>=2147483647 +# define EC_CLZ0 ((int)sizeof(unsigned)*CHAR_BIT) +# define EC_CLZ(_x) (__builtin_clz(_x)) +# elif LONG_MAX>=2147483647L +# define EC_CLZ0 ((int)sizeof(unsigned long)*CHAR_BIT) +# define EC_CLZ(_x) (__builtin_clzl(_x)) +# endif +# endif +#endif + +#if defined(EC_CLZ) +/*Note that __builtin_clz is not defined when _x==0, according to the gcc + documentation (and that of the BSR instruction that implements it on x86). + The majority of the time we can never pass it zero. + When we need to, it can be special cased.*/ +# define EC_ILOG(_x) (EC_CLZ0-EC_CLZ(_x)) +#else +static int ec_ilog2(celt_uint32 _v){ + int ret; + int m; + ret=!!_v; + m=!!(_v&0xFFFF0000)<<4; + _v>>=m; + ret|=m; + m=!!(_v&0xFF00)<<3; + _v>>=m; + ret|=m; + m=!!(_v&0xF0)<<2; + _v>>=m; + ret|=m; + m=!!(_v&0xC)<<1; + _v>>=m; + ret|=m; + ret+=!!(_v&0x2); + return ret; +} +# define EC_ILOG(_x) (ec_ilog2(_x)) +#endif + +#endif