pax_global_header00006660000000000000000000000064113201627320014507gustar00rootroot0000000000000052 comment=d457da7bd37a020cbd36e6f61fae5e42aa28e183 aften/000077500000000000000000000000001132016273200121505ustar00rootroot00000000000000aften/API C#.txt000066400000000000000000000070241132016273200135330ustar00rootroot00000000000000Some notes about using the Aften C# API by Prakash Punnoor ================================================================================== In contrast to the native C API, the C# bindings allow a high-level use of Aften. At the end of the document you can find a running example to hackishly convert a standard 44,1kHz 16bit PCM Stereo file, as you can find on CD-DA. The context object from the C API is just lightly wrapped, so bear with me. So, before initializing the encoder you should set up your context object. The best is, to get one filled with default values by calling the static GetDefaultsContext() method. Then set it up and pass it to the constructor of the FrameEncoderTSample, where TSample denotes the type of samples you want to convert. If you have samples made of short integeres, you would use FrameEncoderInt16. If you don't cast the object, you will have strongly- typed Encode functions which take Arrays of TSamples. You can also cast down to the FrameEncoder base class, which takes generic Arrays. Nevertheless the allowed type is determined by the class you instantiate. Keep in mind that the context object is a value type! I stumbled a few times upon it... There will be several overloads of Encode functions available, which allow passing of arrays or streams. You can also decide whether you want to pass a stream where the output stream is written or you'll get a MemoryStream back (with position set at the end). (You are free to mix the functions if you like.) Remember to call the Flush function, when you are done with encoding, as Aften will still return frames. As a convenience a EncodeAndFlush function exists, which can be used to encode a complete stream in one shot, as it is done in the example. At the end dispose the encoder, as otherwise the finalizer would be called sometime in the future which you don't really want. To get some status back while encoding you can subscribe to the FrameEncoded event. You can abort an encode with the Abort function (from another thread), though you'll have to dispose the instance afterwards. Remember that the C# bindings are still incomplete and will evolve with time, but I'll be happy to receive some feedback. The example program: using System; using System.IO; using Aften; namespace AftenTest { public class Test { public static int Main( string[] args ) { Console.WriteLine( "Aften AC3 Encoding Demo" ); if ( args.Length != 2 ) { Console.WriteLine( "Usage: " + Path.GetFileNameWithoutExtension( Environment.CommandLine ) + " " ); return -1; } EncodingContext context = FrameEncoder.GetDefaultsContext(); context.Channels = 2; context.SampleRate = 44100; context.AudioCodingMode = AudioCodingMode.Stereo; context.HasLfe = false; using ( FileStream inputStream = new FileStream( args[0], FileMode.Open ) ) using ( FileStream outputStream = new FileStream( args[1], FileMode.Create ) ) using ( FrameEncoder encoder = new FrameEncoderInt16( ref context ) ) { inputStream.Seek( 44, SeekOrigin.Begin ); // Skip WAVE header... encoder.FrameEncoded += new EventHandler( encoder_FrameEncoded ); encoder.EncodeAndFlush( inputStream, outputStream ); } Console.WriteLine( "Done" ); Console.ReadLine(); return 0; } private static void encoder_FrameEncoded( object sender, FrameEventArgs e ) { if ( e.FrameNumber % 100 == 1 ) Console.WriteLine( "Frame: " + e.FrameNumber + " Size: " + e.Size + " Quality: " + e.Status.Quality ); } } }aften/API.txt000066400000000000000000000051011132016273200133170ustar00rootroot00000000000000Some notes about using the API ============================== Aften in threaded mode gives back frames with a latency depending of the amount of threads used. You can think of Aften using some sort of internal queue, which needs to be filled, prior you get encoded frames back. That means, if Aften runs with n threads, the first n calls to aften_encode_frame will immediately return with a value of 0. Similarly, once you have no more input samples, the queue must be flushed, before the encoder can be closed. Otherwise you'll have dead-locks or segfaults. So you have to call aften_encode_frame will a NULL samples buffer, so that the encoder flushes the remaining frames. (These contain valid data, of course, so don't forget to handle them properly.) Even if you are *not* in threaded mode, you need to flush the encoder, as it might give back an additional frame due to padding. In case you want to abort the encoder, you can simply call aften_encode_close now. Aften will shut down running threads if needed, and inform you about this via error code. This is a stripped down version of aften.c. You should model your routine similarly if you want to run aften in threaded mode. A side note: Don't think of optimizing away the got_fs_once variable. This will lead to dead-locks if you encode <=n frames. #include "aften.h" int main(int argc, char **argv) { uint8_t *frame_buffer; FLOAT *samples_buffer; AftenContext s; int last_frame = 0; int got_fs_once = 0; int fs = 0; int nr = 0; // init context with default values aften_set_defaults(&s); // set-up AftenContext now, init buffers, etc. // initialize encoder if(aften_encode_init(&s)) { fprintf(stderr, "error initializing encoder\n"); aften_encode_close(&s); return 1; } // main decoding loop do { nr = read_samples(...); // call remapping function here... // encode fs = aften_encode_frame(&s, frame_buffer, samples_buffer, nr);// flush encoder by giving zero count // if got_fs_once is true and than on flushing we get back 0, it means we have to close encoder if(fs < 0) { fprintf(stderr, "Error encoding frame\n"); break; } else { if (fs > 0) { write_frame(...);// write frame with size of fs got_fs_once;// means encoder started outputting samples. } last_frame = nr; } } while(nr > 0 || fs > 0 || !got_fs_once);// we must flush encoder before closing it aften_encode_close(&s); return 0; } aften/CMakeLists.txt000066400000000000000000000344241132016273200147170ustar00rootroot00000000000000# CMake project file by Prakash Punnoor CMAKE_MINIMUM_REQUIRED(VERSION 2.4) IF(COMMAND cmake_policy) cmake_policy(SET CMP0003 NEW) ENDIF(COMMAND cmake_policy) IF(NOT DEFINED CMAKE_BUILD_TYPE) SET(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build, options are: None(CMAKE_CXX_FLAGS or CMAKE_C_FLAGS used) Debug Release RelWithDebInfo MinSizeRel.") ENDIF(NOT DEFINED CMAKE_BUILD_TYPE) SET(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/CMakeModules") Project(Aften C) SET(SO_MAJOR_VERSION "0") SET(SO_MINOR_VERSION "0") SET(SO_BUILD_VERSION "8") SET(SO_VERSION "${SO_MAJOR_VERSION}.${SO_MINOR_VERSION}.${SO_BUILD_VERSION}") IF(${Aften_SOURCE_DIR} MATCHES ${Aften_BINARY_DIR}) MESSAGE("Please do an out-of-tree build:") MESSAGE("rm -f CMakeCache.txt; mkdir -p default; cd default; cmake ..; make") MESSAGE(FATAL_ERROR "in-tree-build detected") ENDIF(${Aften_SOURCE_DIR} MATCHES ${Aften_BINARY_DIR}) INCLUDE(${CMAKE_ROOT}/Modules/TestBigEndian.cmake) INCLUDE(${CMAKE_ROOT}/Modules/CheckCSourceCompiles.cmake) INCLUDE(${CMAKE_MODULE_PATH}/ConfigHelper.cmake) INCLUDE(${CMAKE_MODULE_PATH}/HeaderTests.cmake) INCLUDE(${CMAKE_MODULE_PATH}/FlagsTests.cmake) INCLUDE(${CMAKE_MODULE_PATH}/CompilerVisibility.cmake) INCLUDE(${CMAKE_MODULE_PATH}/CompilerSIMD.cmake) INCLUDE(${CMAKE_MODULE_PATH}/DetectCompiler.cmake) OPTION(SHARED "build shared Aften library" OFF) OPTION(DOUBLE "build Aften with doubles instead of floats" OFF) IF(DOUBLE) ADD_DEFINE(CONFIG_DOUBLE) ENDIF(DOUBLE) OPTION(BINDINGS_CS "build C# bindings" OFF) OPTION(BINDINGS_CXX "build C++ bindings" OFF) IF(BINDINGS_CXX) SET(SHARED ON CACHE BOOL "build shared Aften library" FORCE) ENDIF(BINDINGS_CXX) INCLUDE_DIRECTORIES(${Aften_BINARY_DIR}/) INCLUDE_DIRECTORIES(${Aften_SOURCE_DIR}/) INCLUDE_DIRECTORIES(${Aften_SOURCE_DIR}/libaften) INCLUDE_DIRECTORIES(${Aften_SOURCE_DIR}/aften) INCLUDE_DIRECTORIES(${Aften_SOURCE_DIR}/pcm) SET(LIBAFTEN_SRCS libaften/a52enc.h libaften/a52enc.c libaften/a52.h libaften/a52.c libaften/a52tab.h libaften/a52tab.c libaften/bitalloc.h libaften/bitalloc.c libaften/bitio.h libaften/bitio.c libaften/crc.h libaften/crc.c libaften/dynrng.h libaften/dynrng.c libaften/window.h libaften/window.c libaften/mdct.h libaften/mdct.c libaften/exponent.h libaften/exponent.c libaften/filter.h libaften/filter.c libaften/util.c libaften/convert.h libaften/convert.c libaften/threading.h libaften/a52dec.h libaften/aften.h libaften/aften-types.h libaften/cpu_caps.h libaften/mem.h common.h bswap.h) SET(LIBAFTEN_X86_SRCS libaften/x86/cpu_caps.c libaften/x86/cpu_caps.h libaften/x86/asm_common.h libaften/x86/asm_support.h libaften/x86/gas_support.h libaften/x86/intelas_support.h) SET(LIBAFTEN_X86_MMX_SRCS libaften/x86/exponent_mmx.c libaften/x86/exponent.h libaften/x86/simd_support.h) SET(LIBAFTEN_X86_SSE_SRCS libaften/x86/mdct_sse.c libaften/x86/mdct_common_sse.c libaften/x86/mdct_common_sse.h libaften/x86/mdct.h libaften/x86/window_sse.c libaften/x86/window.h libaften/x86/simd_support.h) SET(LIBAFTEN_X86_SSE2_SRCS libaften/x86/exponent_sse2.c libaften/x86/exponent.h libaften/x86/simd_support.h) SET(LIBAFTEN_X86_SSE3_SRCS libaften/x86/mdct_sse3.c libaften/x86/mdct_common_sse.h libaften/x86/mdct.h libaften/x86/simd_support.h) SET(LIBAFTEN_PPC_SRCS libaften/ppc/cpu_caps.c libaften/ppc/cpu_caps.h) SET(LIBAFTEN_ALTIVEC_SRCS libaften/ppc/mdct_altivec.c libaften/ppc/mdct.h libaften/ppc/altivec_common.h) SET(AFTEN_SRCS aften/aften.c aften/opts.c aften/opts.h aften/helptext.h) SET(PCM_SRCS pcm/aiff.c pcm/byteio.c pcm/byteio.h pcm/caff.c pcm/convert.c pcm/formats.c pcm/formats.h pcm/pcm.c pcm/pcm.h pcm/pcmfile.c pcm/pcmfile.h pcm/pcm_io.c pcm/raw.c pcm/wav.c) IF(CMAKE_UNAME) EXEC_PROGRAM(uname ARGS -m OUTPUT_VARIABLE CMAKE_SYSTEM_MACHINE) ELSE(CMAKE_UNAME) IF(CMAKE_SYSTEM MATCHES "Windows" AND CMAKE_SYSTEM_PROCESSOR MATCHES "x86") IF(CMAKE_SIZEOF_VOID_P MATCHES "8") SET(CMAKE_SYSTEM_MACHINE "x86_64") ELSE(CMAKE_SIZEOF_VOID_P MATCHES "8") SET(CMAKE_SYSTEM_MACHINE "i386") ENDIF(CMAKE_SIZEOF_VOID_P MATCHES "8") ELSE(CMAKE_SYSTEM MATCHES "Windows" AND CMAKE_SYSTEM_PROCESSOR MATCHES "x86") MESSAGE(FATAL_ERROR "Could not detect machine type") ENDIF(CMAKE_SYSTEM MATCHES "Windows" AND CMAKE_SYSTEM_PROCESSOR MATCHES "x86") ENDIF(CMAKE_UNAME) DETECT_COMPILER() CHECK_64BITS() IF(CMAKE_COMPILER_IS_GNUCC) SET(CMAKE_C_FLAGS_RELEASE "-funroll-loops -fomit-frame-pointer ${CMAKE_C_FLAGS_RELEASE}") SET(ADD_CFLAGS "-pedantic -Wall -Wpointer-arith -Wredundant-decls -Wformat -Wunused ${ADD_CFLAGS}") # gcc 2.9.5 doesn't know following CHECK_CFLAGS_APPEND(ADD_EXCLUSIVE_CFLAGS "-std=gnu99") CHECK_CFLAGS_APPEND(ADD_CFLAGS "-Wdisabled-optimization") CHECK_CFLAGS_APPEND(ADD_CFLAGS "-Wfloat-equal") CHECK_CFLAGS_APPEND(ADD_EXCLUSIVE_CFLAGS "-Wbad-function-cast") # gcc 3.0 doesn't know following CHECK_CFLAGS_APPEND(ADD_EXCLUSIVE_CFLAGS "-Wdeclaration-after-statement") CHECK_CFLAGS_APPEND(ADD_CFLAGS "-Wextra") CHECK_CFLAGS_APPEND(ADD_CFLAGS "-Wno-switch") # gcc 4.1 doesn't know following CHECK_CFLAGS_APPEND(ADD_CFLAGS "-Wstrict-overflow") ENDIF(CMAKE_COMPILER_IS_GNUCC) IF(CMAKE_COMPILER_IS_ICC) SET(CMAKE_C_FLAGS_RELEASE "-O3 -funroll-loops -fomit-frame-pointer ${CMAKE_C_FLAGS_RELEASE}") SET(ADD_CFLAGS "-std=c99 -Wall -wd810 ${ADD_CFLAGS}") ENDIF(CMAKE_COMPILER_IS_ICC) IF(MSVC) # msvc ignores bogus options, so detection makes no sense SET(CMAKE_C_FLAGS_RELEASE "/Ot /Oy /Oi /Ox ${CMAKE_C_FLAGS_RELEASE}") ADD_DEFINITIONS(-D_CRT_SECURE_NO_DEPRECATE) ENDIF(MSVC) TEST_BIG_ENDIAN(CMAKE_WORDS_BIGENDIAN) IF(CMAKE_WORDS_BIGENDIAN) ADD_DEFINE(WORDS_BIGENDIAN) ENDIF(CMAKE_WORDS_BIGENDIAN) IF(UNIX) SET(LIBM "m") TEST_COMPILER_VISIBILITY() IF(APPLE) ADD_DEFINE(SYS_DARWIN) ELSE(APPLE) CHECK_FUNCTION_DEFINE("#include " "get_nprocs" "()" HAVE_GET_NPROCS) IF(NOT HAVE_GET_NPROCS) MESSAGE(STATUS "Hardcoding 2 threads usage") ADD_DEFINE("NUM_THREADS 2") ENDIF(NOT HAVE_GET_NPROCS) ENDIF(APPLE) ENDIF(UNIX) # threads handling FIND_PACKAGE(Threads) IF(CMAKE_USE_WIN32_THREADS_INIT) ADD_DEFINE(HAVE_WINDOWS_THREADS) IF(MINGW) ADD_DEFINE(MINGW_ALIGN_STACK_HACK) ENDIF(MINGW) ELSE(CMAKE_USE_WIN32_THREADS_INIT) IF(CMAKE_USE_PTHREADS_INIT) ADD_DEFINE(HAVE_POSIX_THREADS) SET(ADD_LIBS ${ADD_LIBS} ${CMAKE_THREAD_LIBS_INIT}) ENDIF(CMAKE_USE_PTHREADS_INIT) ENDIF(CMAKE_USE_WIN32_THREADS_INIT) ADD_DEFINE("MAX_NUM_THREADS 32") ADD_DEFINITIONS(-D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE) CHECK_INCLUDE_FILE_DEFINE(inttypes.h HAVE_INTTYPES_H) CHECK_INCLUDE_FILE_DEFINE(byteswap.h HAVE_BYTESWAP_H) # output GIT version to config.h EXECUTE_PROCESS(COMMAND git log -1 --pretty=format:%h OUTPUT_VARIABLE GIT_VERSION ERROR_QUIET) IF(GIT_VERSION) ADD_DEFINE("GIT_VERSION \"${GIT_VERSION}\"") ENDIF(GIT_VERSION) CHECK_POSIX_MEMALIGN() # do SIMD stuff IF(CMAKE_SYSTEM_MACHINE MATCHES "i.86" OR CMAKE_SYSTEM_MACHINE MATCHES "x86_64") CHECK_MMX() # MSVC doesn't have MMX support in x64 mode, so check for SSE independently CHECK_SSE() IF(HAVE_MMX OR HAVE_SSE) INCLUDE_DIRECTORIES(${Aften_SOURCE_DIR}/libaften/x86) SET(LIBAFTEN_SRCS ${LIBAFTEN_SRCS} ${LIBAFTEN_X86_SRCS}) ADD_DEFINE(HAVE_CPU_CAPS_DETECTION) ENDIF(HAVE_MMX OR HAVE_SSE) IF(HAVE_MMX) SET(LIBAFTEN_SRCS ${LIBAFTEN_SRCS} ${LIBAFTEN_X86_MMX_SRCS}) SET(SIMD_FLAGS "${SIMD_FLAGS} ${MMX_FLAGS} -DUSE_MMX") FOREACH(SRC ${LIBAFTEN_X86_MMX_SRCS}) SET_SOURCE_FILES_PROPERTIES(${SRC} PROPERTIES COMPILE_FLAGS ${SIMD_FLAGS}) ENDFOREACH(SRC) ADD_DEFINE(HAVE_MMX) ENDIF(HAVE_MMX) IF(HAVE_SSE) SET(SIMD_FLAGS "${SIMD_FLAGS} ${SSE_FLAGS} -DUSE_SSE") IF(NOT DOUBLE) SET(LIBAFTEN_SRCS ${LIBAFTEN_SRCS} ${LIBAFTEN_X86_SSE_SRCS}) FOREACH(SRC ${LIBAFTEN_X86_SSE_SRCS}) SET_SOURCE_FILES_PROPERTIES(${SRC} PROPERTIES COMPILE_FLAGS ${SIMD_FLAGS}) ENDFOREACH(SRC) ENDIF(NOT DOUBLE) ADD_DEFINE(HAVE_SSE) CHECK_SSE2() IF(HAVE_SSE2) SET(SIMD_FLAGS "${SIMD_FLAGS} ${SSE2_FLAGS} -DUSE_SSE2") SET(LIBAFTEN_SRCS ${LIBAFTEN_SRCS} ${LIBAFTEN_X86_SSE2_SRCS}) FOREACH(SRC ${LIBAFTEN_X86_SSE2_SRCS}) SET_SOURCE_FILES_PROPERTIES(${SRC} PROPERTIES COMPILE_FLAGS ${SIMD_FLAGS}) ENDFOREACH(SRC) ADD_DEFINE(HAVE_SSE2) CHECK_SSE3() IF(HAVE_SSE3) SET(SIMD_FLAGS "${SIMD_FLAGS} ${SSE3_FLAGS} -DUSE_SSE3") IF(NOT DOUBLE) SET(LIBAFTEN_SRCS ${LIBAFTEN_SRCS} ${LIBAFTEN_X86_SSE3_SRCS}) FOREACH(SRC ${LIBAFTEN_X86_SSE3_SRCS}) SET_SOURCE_FILES_PROPERTIES(${SRC} PROPERTIES COMPILE_FLAGS ${SIMD_FLAGS}) ENDFOREACH(SRC) ENDIF(NOT DOUBLE) ADD_DEFINE(HAVE_SSE3) CHECK_CASTSI128() ENDIF(HAVE_SSE3) ENDIF(HAVE_SSE2) ENDIF(HAVE_SSE) ENDIF(CMAKE_SYSTEM_MACHINE MATCHES "i.86" OR CMAKE_SYSTEM_MACHINE MATCHES "x86_64") IF(CMAKE_SYSTEM_MACHINE MATCHES "Power Macintosh" OR CMAKE_SYSTEM_MACHINE MATCHES "ppc") CHECK_ALTIVEC() IF(HAVE_ALTIVEC AND NOT DOUBLE) INCLUDE_DIRECTORIES(${Aften_SOURCE_DIR}/libaften/ppc) SET(LIBAFTEN_SRCS ${LIBAFTEN_SRCS} ${LIBAFTEN_PPC_SRCS}) SET(LIBAFTEN_SRCS ${LIBAFTEN_SRCS} ${LIBAFTEN_ALTIVEC_SRCS}) FOREACH(SRC ${LIBAFTEN_ALTIVEC_SRCS}) SET_SOURCE_FILES_PROPERTIES(${SRC} PROPERTIES COMPILE_FLAGS "-maltivec") ENDFOREACH(SRC) ADD_DEFINE(HAVE_ALTIVEC) ENDIF(HAVE_ALTIVEC AND NOT DOUBLE) ENDIF(CMAKE_SYSTEM_MACHINE MATCHES "Power Macintosh" OR CMAKE_SYSTEM_MACHINE MATCHES "ppc") GENERATE_CONFIG_H() SET(CMAKE_C_FLAGS "${ADD_CFLAGS} ${ADD_EXCLUSIVE_CFLAGS} ${CMAKE_C_FLAGS}") IF(SHARED) ADD_LIBRARY(aften SHARED ${LIBAFTEN_SRCS}) SET_TARGET_PROPERTIES(aften PROPERTIES VERSION ${SO_VERSION} SOVERSION ${SO_MAJOR_VERSION}) SET_TARGET_PROPERTIES(aften PROPERTIES LINKER_LANGUAGE C) SET_TARGET_PROPERTIES(aften PROPERTIES DEFINE_SYMBOL AFTEN_BUILD_LIBRARY) TARGET_LINK_LIBRARIES(aften ${LIBM} ${ADD_LIBS}) SET(INSTALL_TARGETS ${INSTALL_TARGETS} aften) ENDIF(SHARED) ADD_LIBRARY(aften_static STATIC ${LIBAFTEN_SRCS}) #SET_TARGET_PROPERTIES(aften_static PROPERTIES OUTPUT_NAME aften) SET_TARGET_PROPERTIES(aften_static PROPERTIES LINKER_LANGUAGE C) SET_TARGET_PROPERTIES(aften_static PROPERTIES COMPILE_FLAGS -DAFTEN_BUILD_LIBRARY) TARGET_LINK_LIBRARIES(aften_static ${LIBM} ${ADD_LIBS}) # building a separate static lib for the pcm audio decoder ADD_LIBRARY(aften_pcm STATIC ${PCM_SRCS}) ADD_EXECUTABLE(aften_exe ${AFTEN_SRCS}) SET_TARGET_PROPERTIES(aften_exe PROPERTIES OUTPUT_NAME aften) SET_TARGET_PROPERTIES(aften_exe PROPERTIES LINKER_LANGUAGE C) IF(WIN32) # When linking to static aften, dllimport mustn't be used SET_TARGET_PROPERTIES(aften_exe PROPERTIES COMPILE_FLAGS -DAFTEN_BUILD_LIBRARY) ENDIF(WIN32) TARGET_LINK_LIBRARIES(aften_exe aften_pcm aften_static) ADD_EXECUTABLE(wavinfo util/wavinfo.c) TARGET_LINK_LIBRARIES(wavinfo aften_pcm) ADD_EXECUTABLE(wavrms util/wavrms.c) TARGET_LINK_LIBRARIES(wavrms aften_pcm ${LIBM}) ADD_EXECUTABLE(wavfilter util/wavfilter.c libaften/filter.c) TARGET_LINK_LIBRARIES(wavfilter aften_pcm ${LIBM}) IF(BINDINGS_CXX) MESSAGE("## WARNING: The C++ bindings are only lightly tested. Feed-back appreciated. ##") Project(Aften CXX) SET(CMAKE_CXX_FLAGS_RELEASE "${ADD_CFLAGS} ${CMAKE_C_FLAGS_RELEASE}") INCLUDE_DIRECTORIES(${Aften_SOURCE_DIR}/bindings) ADD_LIBRARY(aftenxx SHARED bindings/aftenxx.cxx) SET_TARGET_PROPERTIES(aftenxx PROPERTIES VERSION ${SO_VERSION} SOVERSION ${SO_MAJOR_VERSION}) SET_TARGET_PROPERTIES(aftenxx PROPERTIES LINKER_LANGUAGE CXX) SET_TARGET_PROPERTIES(aftenxx PROPERTIES DEFINE_SYMBOL AFTENXX_BUILD_LIBRARY) TARGET_LINK_LIBRARIES(aftenxx aften) SET(INSTALL_TARGETS ${INSTALL_TARGETS} aftenxx) SET(INSTALL_HEADERS ${INSTALL_HEADERS} bindings/aftenxx.h) ENDIF(BINDINGS_CXX) IF(BINDINGS_CS) MESSAGE("## WARNING: The C# bindings are not completed, but tested (see \"API C#.txt\"). ##") SET(AFTENSHARP_SRCS bindings/cs/AftenTypes.cs bindings/cs/FrameEncoder.cs bindings/cs/FrameEventArgs.cs bindings/cs/Utility.cs) IF(WIN32) SET(WIN_SRCS "") FOREACH(SRC ${AFTENSHARP_SRCS}) STRING(REPLACE "/" "\\" WIN_SRC ${SRC}) SET(WIN_SRCS ${WIN_SRCS} ${WIN_SRC}) ENDFOREACH(SRC ${AFTENSHARP_SRCS}) SET(AFTENSHARP_SRCS ${WIN_SRCS}) ENDIF(WIN32) SET(AFTENSHARP_DLL ${Aften_BINARY_DIR}/AftenSharp.dll) FIND_PROGRAM( CSCOMPILER NAMES csc gmcs) IF(CSCOMPILER MATCHES "NOTFOUND") MESSAGE(SEND_ERROR "Could not locate a supported C# compiler") ENDIF(CSCOMPILER MATCHES "NOTFOUND") ADD_CUSTOM_COMMAND( OUTPUT ${AFTENSHARP_DLL} COMMAND ${CSCOMPILER} -t:library -out:${AFTENSHARP_DLL} -o+ ${AFTENSHARP_SRCS} DEPENDS ${AFTENSHARP_SRCS} WORKING_DIRECTORY ${Aften_SOURCE_DIR}) ADD_CUSTOM_TARGET( AftenSharp ALL DEPENDS ${AFTENSHARP_DLL}) ENDIF(BINDINGS_CS) INSTALL(TARGETS ${INSTALL_TARGETS} aften_exe wavinfo wavrms wavfilter RUNTIME DESTINATION bin LIBRARY DESTINATION lib${LIB_SUFFIX} ARCHIVE DESTINATION lib${LIB_SUFFIX}) INSTALL(FILES ${INSTALL_HEADERS} libaften/aften.h libaften/aften-types.h DESTINATION include/aften) aften/CMakeModules/000077500000000000000000000000001132016273200144615ustar00rootroot00000000000000aften/CMakeModules/CompilerSIMD.cmake000066400000000000000000000051161132016273200177150ustar00rootroot00000000000000MACRO(CHECK_MM_MALLOC) SET(CMAKE_REQUIRED_FLAGS "${SSE_FLAGS}") CHECK_C_SOURCE_COMPILES( "#include int main(){_mm_malloc(1024,16);} " HAVE_MM_MALLOC) SET(CMAKE_REQUIRED_FLAGS "") IF(HAVE_MM_MALLOC) ADD_DEFINE(HAVE_MM_MALLOC) ENDIF(HAVE_MM_MALLOC) ENDMACRO(CHECK_MM_MALLOC) MACRO(CHECK_POSIX_MEMALIGN) CHECK_C_SOURCE_COMPILES( "#define _XOPEN_SOURCE 600 #include int main(){ void *test; posix_memalign(&test, 16, 1024); } " HAVE_POSIX_MEMALIGN) SET(CMAKE_REQUIRED_FLAGS "") IF(HAVE_POSIX_MEMALIGN) ADD_DEFINE(HAVE_POSIX_MEMALIGN) ENDIF(HAVE_POSIX_MEMALIGN) ENDMACRO(CHECK_POSIX_MEMALIGN) MACRO(CHECK_CASTSI128) SET(CMAKE_REQUIRED_FLAGS "${SSE3_FLAGS}") CHECK_C_SOURCE_COMPILES( "#include int main(){__m128i X; _mm_castsi128_ps(X);} " HAVE_CASTSI128) SET(CMAKE_REQUIRED_FLAGS "") IF(NOT HAVE_CASTSI128) ADD_DEFINE(EMU_CASTSI128) ENDIF(NOT HAVE_CASTSI128) ENDMACRO(CHECK_CASTSI128) MACRO(CHECK_MMX) IF(CMAKE_COMPILER_IS_GNUCC) SET(MMX_FLAGS "-mmmx") ENDIF(CMAKE_COMPILER_IS_GNUCC) SET(CMAKE_REQUIRED_FLAGS "${MMX_FLAGS}") CHECK_C_SOURCE_COMPILES( "#include int main() { __m64 X = _mm_setzero_si64(); __m64 Y = _mm_unpackhi_pi8(X, X); _mm_empty(); } " HAVE_MMX) SET(CMAKE_REQUIRED_FLAGS "") ENDMACRO(CHECK_MMX) MACRO(CHECK_SSE) IF(CMAKE_COMPILER_IS_GNUCC) SET(SSE_FLAGS "-mmmx -msse") ENDIF(CMAKE_COMPILER_IS_GNUCC) SET(CMAKE_REQUIRED_FLAGS "${SSE_FLAGS}") CHECK_C_SOURCE_COMPILES( "#include int main(){__m128 X = _mm_setzero_ps();} " HAVE_SSE) SET(CMAKE_REQUIRED_FLAGS "") ENDMACRO(CHECK_SSE) MACRO(CHECK_SSE2) IF(CMAKE_COMPILER_IS_GNUCC) SET(SSE2_FLAGS "-mmmx -msse -msse2") ENDIF(CMAKE_COMPILER_IS_GNUCC) SET(CMAKE_REQUIRED_FLAGS "${SSE2_FLAGS}") CHECK_C_SOURCE_COMPILES( "#include int main() { __m128i X = _mm_setzero_si128(); __m128i Y = _mm_unpackhi_epi8(X, X); } " HAVE_SSE2) SET(CMAKE_REQUIRED_FLAGS "") ENDMACRO(CHECK_SSE2) MACRO(CHECK_SSE3) IF(CMAKE_COMPILER_IS_GNUCC) SET(SSE3_FLAGS "-mmmx -msse -msse2 -msse3") ENDIF(CMAKE_COMPILER_IS_GNUCC) SET(CMAKE_REQUIRED_FLAGS "${SSE3_FLAGS}") CHECK_C_SOURCE_COMPILES( "#include int main() { __m128 X = _mm_setzero_ps(); __m128 Y = _mm_movehdup_ps(X); } " HAVE_SSE3) SET(CMAKE_REQUIRED_FLAGS "") ENDMACRO(CHECK_SSE3) MACRO(CHECK_ALTIVEC) IF(CMAKE_COMPILER_IS_GNUCC) SET(ALTIVEC_FLAGS "-maltivec") ENDIF(CMAKE_COMPILER_IS_GNUCC) SET(CMAKE_REQUIRED_FLAGS "${ALTIVEC_FLAGS}") CHECK_C_SOURCE_COMPILES( "#include int main() { vector unsigned char v1, v2, v3; v1 = vec_add(v2, v3); } " HAVE_ALTIVEC) SET(CMAKE_REQUIRED_FLAGS "") ENDMACRO(CHECK_ALTIVEC) aften/CMakeModules/CompilerVisibility.cmake000066400000000000000000000030661132016273200213120ustar00rootroot00000000000000MACRO(TEST_COMPILER_VISIBILITY) IF(NOT WIN32 AND NOT CMAKE_COMPILER_IS_ICC) SET(CMAKE_REQUIRED_FLAGS "-fvisibility=hidden") CHECK_C_SOURCE_COMPILES( "void __attribute__((visibility(\"default\"))) test() {} #ifdef __INTEL_COMPILER #error ICC breaks with binutils and visibility #endif int main(){} " HAVE_VISIBILITY) SET(CMAKE_REQUIRED_FLAGS "") IF(HAVE_VISIBILITY) SET(ADD_CFLAGS "${ADD_CFLAGS} -fvisibility=hidden") ADD_DEFINITIONS(-DHAVE_GCC_VISIBILITY) ENDIF(HAVE_VISIBILITY) ENDIF(NOT WIN32 AND NOT CMAKE_COMPILER_IS_ICC) ENDMACRO(TEST_COMPILER_VISIBILITY) MACRO(TEST_NASM_COMPILER_VISIBILITY) IF(NOT DEFINED HAVE_NASM_VISIBILITY) MESSAGE(STATUS "Performing Test HAVE_NASM_VISIBILITY") SET(SOURCE "global _foo:function hidden\n_foo:") FILE(WRITE "${CMAKE_BINARY_DIR}/CMakeFiles/CMakeTmp/src.nasm" "${SOURCE}") TRY_COMPILE(HAVE_NASM_VISIBILITY ${CMAKE_BINARY_DIR} ${CMAKE_BINARY_DIR}/CMakeFiles/CMakeTmp/src.nasm OUTPUT_VARIABLE OUTPUT) WRITE_FILE(${CMAKE_BINARY_DIR}/CMakeFiles/CMakeOutput.log "Performing nasm visibility test with the following output:\n" "${OUTPUT}\n" "Source file was:\n${SOURCE}\n" APPEND) IF(HAVE_NASM_VISIBILITY) MESSAGE(STATUS "Performing Test HAVE_NASM_VISIBILITY - Success") ELSE(HAVE_NASM_VISIBILITY) MESSAGE(STATUS "Performing Test HAVE_NASM_VISIBILITY - Failure") ENDIF(HAVE_NASM_VISIBILITY) ENDIF(NOT DEFINED HAVE_NASM_VISIBILITY) IF(HAVE_NASM_VISIBILITY) SET(CMAKE_ASM_FLAGS "-DHAVE_NASM_VISIBILITY") ENDIF(HAVE_NASM_VISIBILITY) ENDMACRO(TEST_NASM_COMPILER_VISIBILITY)aften/CMakeModules/ConfigHelper.cmake000066400000000000000000000014021132016273200200250ustar00rootroot00000000000000# config.h magic SET(CONFIG_H_VALS_OLD "${CONFIG_H_VALS}") SET(CONFIG_H_VALS "" CACHE INTERNAL "") SET(CONFIG_H_FILE ${CMAKE_BINARY_DIR}/config.h) INCLUDE_DIRECTORIES(${CMAKE_BINARY_DIR}) ADD_DEFINITIONS(-DHAVE_CONFIG_H) MACRO(ADD_DEFINE ARG) SET(CONFIG_H_CONTENT "${CONFIG_H_CONTENT}#define ${ARG} ") # can't cache mulitline values SET(CONFIG_H_VALS "${CONFIG_H_VALS}${ARG}" CACHE INTERNAL "") ENDMACRO(ADD_DEFINE ARG) MACRO(GENERATE_CONFIG_H) # Generate config.h only if values differ IF(NOT CONFIG_H_VALS_OLD STREQUAL CONFIG_H_VALS OR NOT EXISTS ${CONFIG_H_FILE}) MESSAGE(STATUS "Writing config.h") FILE(WRITE ${CONFIG_H_FILE} "${CONFIG_H_CONTENT}") ENDIF(NOT CONFIG_H_VALS_OLD STREQUAL CONFIG_H_VALS OR NOT EXISTS ${CONFIG_H_FILE}) ENDMACRO(GENERATE_CONFIG_H)aften/CMakeModules/DetectCompiler.cmake000066400000000000000000000015761132016273200203770ustar00rootroot00000000000000MACRO(DETECT_COMPILER) IF(NOT CMAKE_COMPILER_IS_GNUCC) CHECK_C_SOURCE_COMPILES( "#ifndef __INTEL_COMPILER #error no icc #endif int main(){} " CMAKE_COMPILER_IS_ICC) ENDIF(NOT CMAKE_COMPILER_IS_GNUCC) ENDMACRO(DETECT_COMPILER) MACRO(MACRO_TEST ARG VAR) CHECK_C_SOURCE_COMPILES( "#ifndef ${ARG} #error ${ARG} macro not defined #endif int main(){} " ${VAR}) ENDMACRO(MACRO_TEST) #check whether we are 32/64 bits cross-compiling MACRO(CHECK_64BITS) IF(CMAKE_COMPILER_IS_GNUCC) MACRO_TEST(__LP64__ HAVE_64BITS) IF(HAVE_64BITS AND CMAKE_SYSTEM_MACHINE MATCHES "i.86") SET(CMAKE_SYSTEM_MACHINE "x86_64") ENDIF(HAVE_64BITS AND CMAKE_SYSTEM_MACHINE MATCHES "i.86") IF(NOT HAVE_64BITS AND CMAKE_SYSTEM_MACHINE MATCHES "x86_64") SET(CMAKE_SYSTEM_MACHINE "i686") ENDIF(NOT HAVE_64BITS AND CMAKE_SYSTEM_MACHINE MATCHES "x86_64") ENDIF(CMAKE_COMPILER_IS_GNUCC) ENDMACRO(CHECK_64BITS) aften/CMakeModules/FlagsTests.cmake000066400000000000000000000011041132016273200175360ustar00rootroot00000000000000#INCLUDE(${CMAKE_ROOT}/Modules/CheckCCompilerFlag.cmake) MACRO(CHECK_CFLAGS_APPEND DEST_FLAGS FLAG) STRING(REGEX REPLACE "^-+(.*)$" "\\1" FLAG_NAME ${FLAG}) STRING(REGEX REPLACE "[-]" "_" FLAG_NAME "${FLAG_NAME}" ) STRING(TOUPPER ${FLAG_NAME} FLAG_NAME) SET(HAVE_FLAG "HAVE_FLAG_${FLAG_NAME}") #CHECK_C_COMPILER_FLAG("${FLAG}" ${HAVE_FLAG}) SET(CMAKE_REQUIRED_FLAGS "${FLAG}") CHECK_C_SOURCE_COMPILES( "int main(){} " ${HAVE_FLAG}) SET(CMAKE_REQUIRED_FLAGS "") IF(${HAVE_FLAG}) SET(${DEST_FLAGS} "${FLAG} ${${DEST_FLAGS}}") ENDIF(${HAVE_FLAG}) ENDMACRO(CHECK_CFLAGS_APPEND)aften/CMakeModules/HeaderTests.cmake000066400000000000000000000006751132016273200177060ustar00rootroot00000000000000INCLUDE(${CMAKE_ROOT}/Modules/CheckIncludeFile.cmake) MACRO(CHECK_INCLUDE_FILE_DEFINE HEADER VAR) CHECK_INCLUDE_FILE(${HEADER} ${VAR}) IF(${VAR}) ADD_DEFINE("${VAR} 1") ENDIF(${VAR}) ENDMACRO(CHECK_INCLUDE_FILE_DEFINE) MACRO(CHECK_FUNCTION_DEFINE HEADERS FUNC PARAM VAR) CHECK_C_SOURCE_COMPILES( " ${HEADERS} int main(){ ${FUNC} ${PARAM}; } " ${VAR}) IF(${VAR}) ADD_DEFINE("${VAR} 1") ENDIF(${VAR}) ENDMACRO(CHECK_FUNCTION_DEFINE HEADERS) aften/COPYING000066400000000000000000000634741132016273200132210ustar00rootroot00000000000000 GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 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. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! aften/Changelog000066400000000000000000000111561132016273200137660ustar00rootroot00000000000000Aften TODO list --------------- - Channel coupling (this will be a large undertaking) - E-AC-3 bitstream format and encoding - ABR encoding mode - 2-pass encoding - Frame parser / analyzer - Option to downmix/upmix/resample prior to encoding - 2-channel surround-matrix downmix - 2-channel headphone downmix - Stereo to 5.1 upmix - Improve DRC implementation - Psychoacoustic model & delta bit allocation - Gapless info using auxdata field - Streaming interface to libaften / internal sample buffer - Better error logging for libaften - pkg-config support or alike - Channel layout support in PCM decoder Aften Changelog --------------- version SVN : current - added Windows x64 support (tested with Visual Studio 2008) - added C# bindings with simple high level API - changed API to simplify its usage - added API.txt - fixed aften error handling - fixed libaften closing in threaded mode, simplifying its usage - AftenContext has a new member called initial_samples. If 256 samples are provided here, the first frame is not padded with zero samples. Nevertheless, you shouldn't use this option unless you need perfect sync, as these first 256 samples can't properly be reconstructed. - fixed bug in wav to ac3 channel remapping - Multiple-file commandline input with channel designation - AIFF file support - CAFF file support - changed API to create a new exponent strategy decision with better quality and more flexibility - rearranged code structure of SIMD optimizations version 0.08 : - fixed piped input from FFmpeg - added support for MPEG channel order remapping - restructured audio input. enables raw pcm file support. - bugfixes in MMX/SSE2 code - stack align hack for x86 MinGW with threads - API changes - SIMD and threads usage is shown and is configurable - screen output gets updated every 200ms to reduce load - SIMD detection changed to compiler-independent inline assembly, thus nasm/yasm not needed anymore version 0.07 : 25 April 2007 - added C++ bindings (pass -DBINDINGS_CXX=1 to cmake to build them) - API change of helper functions - new and more precise bitalloc algorithm - parallelization - optional faster exponent strategy decision - added SSE version of window function - added MMX and SSE2 versions of some exponent related functions - removed old build system - frame-independent variable bandwidth - minimum and maximum bandwidth settings for variable bandwidth mode - altivec support framework (by David Conrad) - altivec MDCT (by David Conrad) version 0.06 : 31 January 2007 - added SSE/SSE3 mdct code (based on vorbis lancer by blacksword8192@hotmail.com) - added runtime SIMD detection code (Prakash Punnoor) - added CMake build system with shared lib/dll support - optional faster bit allocation by reducing accuracy/quality - replaced MDCT code with implementation from libvorbis - added Dynamic Range Compression encoding w/ profile selection - improved exponent strategy decision - accuracy increase in bit allocation - new longhelp option for detailed commandline info version 0.05 : 21 August 2006 - bit allocation speedup by Prakash Punnoor - compile-time choice of using floats or doubles internally - internal restructuring of MDCT functions - more bit allocation speed-ups and bug fixes - quality=0 is now a valid setting version 0.04 : 05 August 2006 - fixed VBR to lower quality if needed to fit in largest available frame size - small adjustment to exponent strategy decision - WAVE_FORMAT_EXTENSIBLE fix by Tebasuna - Alternate bit stream syntax with new commandline options - Better encoding structure - filter library - changed sample type from float to double - moved CRC code to a separate file - LFE low-pass filter - DC high-pass filter - bandwidth low-pass filter - Improved variable bandwidth selection - Channel bandwidth low-pass filter - Created separate library and frontend - changed default mode to CBR - allow for specification of max bitrate in VBR mode version 0.03 : 20 July 2006 - support for WAV with sample types 8-bit, 24-bit, 32-bit, float, or double. - better multi-channel support, better mapping with WAV_FORMAT_EXTENSIBLE. - adjustments to VBR, changed default quality from 200 to 220. - adjustments to variable bandwidth, increased average bandwidth settings. version 0.02 : 09 July 2006 - commandline options and customizable settings for: - mix levels - dialog normalization - dolby surround flag version 0.01 : 09 July 2006 (first versioned release) - simple configure script - piped input and output - 6-channel mapping - corrected defaults for mix levels - commandline options - quiet mode (no console output) - per-frame or average statistics - big-endian support aften/README000066400000000000000000000076261132016273200130430ustar00rootroot00000000000000------------------------------------------------------------------------------- Aften: A/52 audio encoder A simple AC3-compatible audio encoder based on FFmpeg. ------------------------------------------------------------------------------- Aften, Copyright (c) 2006-2009 Justin Ruggles 2006-2009 Prakash Punnoor http://aften.sourceforge.net/ ------------------------------------------------------------------------------- FFmpeg, Copyright (c) 2000-2009 Fabrice Bellard, et al. http://www.ffmpeg.org/ ------------------------------------------------------------------------------- Building Aften with CMake ========================== Note: Avoid gcc-3 if you care for fast vector code. gcc-4.2 generates slow MMX code. Try using gcc-4.1 instead. If your CPU supports SSE2 though, this is not an issue, as the SSE2 code replaces the MMX code and the former is unaffected by the gcc bug. The aim of using CMake is making portable development easier, as CMake contains generators for various build systems. On e.g. *nix Makefiles will be built, and on Windows MS VC++ project files, if you wish. You can get CMake at http://cmake.org/. This document explains briefly how to build with CMake on Linux via an out-of-tree build: - Change to the toplevel directory containing the Aften sources. - Create a directory, e.g. "default", and change into it. - Now run something like: cmake .. -DCMAKE_INSTALL_PREFIX:STRING="/usr" make make install If you exported your CFLAGS, there is no need to specify them explicitly, as CMake will pick them up. - Aften should get installed as you got used to it. I really would like to get CMake building Aften on every supported platform. So please contact me if it doesn't build on yours. I'll try to fix this with your help. Following Options might be of interest for you: SHARED: Builds aften as a shared lib, as well. The API hasn't been set in stone, so you have been warned. ;-) DOUBLE: Builds aften using double precision. Beware that you won't get SIMD code, as the SSE code hasn't been ported to SSE2, yet. BINDINGS_CXX: Builds C++ bindings for aften. Include aftenxx.h in your C++ project and link to aftenxx. You will find aften related classes in the namespace Aften. BINDINGS_CS: Builds C# bindings for aften. Include a reference to AftenSharp.dll in your C# project. You will find aften related classes in the namespace Aften. Some tips: - You can use a console GUI named ccmake for configuring cmake. This also comes in handy, to find out about available options. You can also set options via command-line: ccmake .. -DCMAKE_INSTALL_PREFIX:STRING="/usr" sets the two variables defined on command line and then starts the GUI. Press 'c' the first time and every time you want to commit changes in the config. Finally press 'g' to run the generator. Btw, to set boolean vars from the command line, use -DVAR:BOOL=X, where X is eg. ON or OFF. - If you want more output at compile time, use make VERBOSE=1 - If you want to install to a different directory (using same prefix), use make install DESTDIR=/foo/bar - CMake doesn't have a distclean target by default, so you better really do an out-of-tree build, then you can simply delete its content when you want a distclean... Furthermore it is easier to have different builds using different parameters via out-of-tree builds. - If you are interested in variables to set, take a look into CMakeCache.txt after having run the configuring stage. - If you update your source tree via git and want to rebuild an previously built lib without cleaning, you better at least clear the CMake cache (remove CMakeCache.txt) otherwise a modified CMake project file could result in unwanted behaviour. aften/aften/000077500000000000000000000000001132016273200132455ustar00rootroot00000000000000aften/aften/aften.c000066400000000000000000000274121132016273200145140ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * Copyright (c) 2006 Justin Ruggles * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file aften.c * Commandline encoder frontend */ #include "common.h" #include #include #include #include #ifdef _WIN32 #include #include #endif #include "aften.h" #include "pcm.h" #include "helptext.h" #include "opts.h" static const int acmod_to_ch[8] = { 2, 1, 2, 3, 3, 4, 4, 5 }; static const char *acmod_str[8] = { "dual mono (1+1)", "mono (1/0)", "stereo (2/0)", "3/0", "2/1", "3/1", "2/2", "3/2" }; static void print_intro(FILE *out) { const char *vers = aften_get_version(); fprintf(out, "\nAften: A/52 audio encoder\n" "Version %s\n" "(c) 2006-2009 Justin Ruggles, Prakash Punnoor, et al.\n\n", vers); } static void print_simd_in_use(FILE *out, AftenSimdInstructions *simd_instructions) { fprintf(out, "SIMD usage:"); if (simd_instructions->mmx) fprintf(out, " MMX"); if (simd_instructions->sse) fprintf(out, " SSE"); if (simd_instructions->sse2) fprintf(out, " SSE2"); if (simd_instructions->sse3) fprintf(out, " SSE3"); if (simd_instructions->ssse3) fprintf(out, " SSSE3"); if (simd_instructions->amd_3dnow) fprintf(out, " 3DNOW"); if (simd_instructions->amd_3dnowext) fprintf(out, " 3DNOWEXT"); if (simd_instructions->amd_sse_mmx) fprintf(out, " SSE-MMX"); if (simd_instructions->altivec) fprintf(out, " Altivec"); fprintf(out, "\n"); } int main(int argc, char **argv) { void (*aften_remap)(void *samples, int n, int ch, A52SampleFormat fmt, int acmod) = NULL; uint8_t *frame = NULL; FLOAT *fwav = NULL; int nr, fs, err; FILE *ifp[A52_NUM_SPEAKERS]; FILE *ofp = NULL; PcmContext pf; CommandOptions opts; AftenContext s; uint32_t samplecount, bytecount, t0, t1, percent; FLOAT kbps, qual, bw; int frame_cnt; int input_file_format; enum PcmSampleFormat read_format; /* update output every 200ms */ clock_t update_clock_span = (clock_t)(0.2f * CLOCKS_PER_SEC); clock_t current_clock; clock_t last_update_clock = clock() - update_clock_span; int ret_val = 0; int i; opts.s = &s; aften_set_defaults(&s); err = parse_commandline(argc, argv, &opts); if (err) { if (err == 1) { print_intro(stderr); print_usage(stderr); return 1; } else { print_intro(stdout); if (err == 2) { print_help(stdout); } else if (err == 3) { print_long_help(stdout); } return 0; } } if (s.verbose > 0) { print_intro(stderr); } memset(ifp, 0, A52_NUM_SPEAKERS * sizeof(FILE *)); for (i = 0; i < opts.num_input_files; i++) { if (!strncmp(opts.infile[i], "-", 2)) { #ifdef _WIN32 _setmode(_fileno(stdin), _O_BINARY); #endif ifp[i] = stdin; } else { ifp[i] = fopen(opts.infile[i], "rb"); if (!ifp[i]) { fprintf(stderr, "error opening input file: %s\n", opts.infile[i]); goto error_end; } } } #ifdef CONFIG_DOUBLE read_format = PCM_SAMPLE_FMT_DBL; #else read_format = PCM_SAMPLE_FMT_FLT; #endif // initialize pcmfile using input input_file_format = PCM_FORMAT_UNKNOWN; if (opts.raw_input) input_file_format = PCM_FORMAT_RAW; if (pcm_init(&pf, opts.num_input_files, ifp, read_format, input_file_format)) { fprintf(stderr, "invalid input file(s)\n"); goto error_end; } if (opts.read_to_eof) pcm_set_read_to_eof(&pf, 1); if (opts.raw_input) { pcm_set_source_params(&pf, opts.raw_ch, opts.raw_fmt, opts.raw_order, opts.raw_sr); } // print wav info to console if (s.verbose > 0) { fprintf(stderr, "input format: "); if (opts.num_input_files > 1) fprintf(stderr, "\n"); pcm_print(&pf, stderr); } // if acmod is given on commandline, determine lfe from number of channels if (s.acmod >= 0) { int ch = acmod_to_ch[s.acmod]; if (ch == pf.channels) { if (s.lfe < 0) { s.lfe = 0; } else { if (s.lfe != 0) { fprintf(stderr, "acmod and lfe do not match number of channels\n"); goto error_end; } } } else if (ch == (pf.channels - 1)) { if (s.lfe < 0) { s.lfe = 1; } else { if (s.lfe != 1) { fprintf(stderr, "acmod and lfe do not match number of channels\n"); goto error_end; } } } else { fprintf(stderr, "acmod does not match number of channels\n"); goto error_end; } } else { // if acmod is not given on commandline, determine from WAVE file int ch = pf.channels; if (s.lfe >= 0) { if (s.lfe == 0 && ch == 6) { fprintf(stderr, "cannot encode 6 channels w/o LFE\n"); goto error_end; } else if (s.lfe == 1 && ch == 1) { fprintf(stderr, "cannot encode LFE channel only\n"); goto error_end; } if (s.lfe) { pf.ch_mask |= 0x08; } } if (aften_wav_channels_to_acmod(ch, pf.ch_mask, &s.acmod, &s.lfe)) { fprintf(stderr, "mismatch in channels, acmod, and lfe params\n"); goto error_end; } } // set some encoding parameters using wav info s.channels = pf.channels; s.samplerate = pf.sample_rate; #ifdef CONFIG_DOUBLE s.sample_format = A52_SAMPLE_FMT_DBL; #else s.sample_format = A52_SAMPLE_FMT_FLT; #endif // open output file if (!strncmp(opts.outfile, "-", 2)) { #ifdef _WIN32 _setmode(_fileno(stdout), _O_BINARY); #endif ofp = stdout; } else { ofp = fopen(opts.outfile, "wb"); if (!ofp) { fprintf(stderr, "error opening output file: %s\n", opts.outfile); goto error_end; } } // print ac3 info to console if (s.verbose > 0) { fprintf(stderr, "output format: %d Hz %s", s.samplerate, acmod_str[s.acmod]); if (s.lfe) { fprintf(stderr, " + LFE"); } fprintf(stderr, "\n\n"); } // allocate memory for coded frame and sample buffer frame = calloc(A52_MAX_CODED_FRAME_SIZE, 1); fwav = calloc(A52_SAMPLES_PER_FRAME * s.channels, sizeof(FLOAT)); if (frame == NULL || fwav == NULL) goto error_end; samplecount = bytecount = t0 = t1 = percent = 0; qual = bw = 0.0; frame_cnt = 0; fs = 0; nr = 0; if (opts.chmap == 0) aften_remap = aften_remap_wav_to_a52; else if (opts.chmap == 2) aften_remap = aften_remap_mpeg_to_a52; // Don't pad start with zero samples, use input audio instead. if (!opts.pad_start) { int diff; nr = pcm_read_samples(&pf, fwav, 256); diff = 256 - nr; if (diff > 0) { memmove(fwav + diff * s.channels, fwav, nr); memset(fwav, 0, diff * s.channels * sizeof(FLOAT)); } if (aften_remap) aften_remap(fwav + diff, nr, s.channels, s.sample_format, s.acmod); s.initial_samples = fwav; } // initialize encoder if (aften_encode_init(&s)) { fprintf(stderr, "error initializing encoder\n"); goto error_end; } // print SIMD instructions used print_simd_in_use(stderr, &s.system.wanted_simd_instructions); // print number of threads used fprintf(stderr, "Threads: %i\n\n", s.system.n_threads); do { nr = pcm_read_samples(&pf, fwav, A52_SAMPLES_PER_FRAME); if (aften_remap) aften_remap(fwav, nr, s.channels, s.sample_format, s.acmod); fs = aften_encode_frame(&s, frame, fwav, nr); if (fs < 0) { fprintf(stderr, "Error encoding frame %d\n", frame_cnt); break; } else if (fs > 0) { if (s.verbose > 0) { samplecount += A52_SAMPLES_PER_FRAME; bytecount += fs; qual += s.status.quality; bw += s.status.bwcode; if (s.verbose == 1) { current_clock = clock(); if (current_clock - last_update_clock >= update_clock_span) { t1 = samplecount / pf.sample_rate; if (frame_cnt > 0 && (t1 > t0 || samplecount >= pf.samples)) { kbps = (bytecount * FCONST(8.0) * pf.sample_rate) / (FCONST(1000.0) * samplecount); percent = 0; if (pf.samples > 0) { percent = (uint32_t)((samplecount * FCONST(100.0)) / pf.samples); percent = CLIP(percent, 0, 100); } fprintf(stderr, "\rprogress: %3u%% | q: %4.1f | " "bw: %2.1f | bitrate: %4.1f kbps ", percent, (qual / (frame_cnt+1)), (bw / (frame_cnt+1)), kbps); } t0 = t1; last_update_clock = current_clock; } } else if (s.verbose == 2) { fprintf(stderr, "frame: %7d | q: %4d | bw: %2d | bitrate: %3d kbps\n", frame_cnt, s.status.quality, s.status.bwcode, s.status.bit_rate); } } fwrite(frame, 1, fs, ofp); frame_cnt++; } } while (nr > 0 || fs > 0 || !frame_cnt); if (s.verbose >= 1) { if (samplecount > 0) { kbps = (bytecount * FCONST(8.0) * pf.sample_rate) / (FCONST(1000.0) * samplecount); } else { kbps = 0; } frame_cnt = MAX(frame_cnt, 1); if (s.verbose == 1) { fprintf(stderr, "\rprogress: 100%% | q: %4.1f | bw: %2.1f | bitrate: %4.1f kbps\n\n", (qual / frame_cnt), (bw / frame_cnt), kbps); } else if (s.verbose == 2) { fprintf(stderr, "\n"); fprintf(stderr, "average quality: %4.1f\n", (qual / frame_cnt)); fprintf(stderr, "average bandwidth: %2.1f\n", (bw / frame_cnt)); fprintf(stderr, "average bitrate: %4.1f kbps\n\n", kbps); } } goto end; error_end: ret_val = 1; end: if (fwav) free(fwav); if (frame) free(frame); pcm_close(&pf); for (i = 0; i < opts.num_input_files; i++) { if (ifp[i]) fclose(ifp[i]); } if (ofp) fclose(ofp); if (aften_encode_close(&s)) return 1; return ret_val; } aften/aften/helptext.h000066400000000000000000000770401132016273200152630ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * Copyright (c) 2007 Justin Ruggles * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file helptext.h * string constants for commandline help and longhelp */ #ifndef HELPTEXT_H #define HELPTEXT_H static const char *usage_heading = "usage: aften [options] \n"; #define HELP_OPTIONS_COUNT 43 static const char *help_options[HELP_OPTIONS_COUNT] = { " [-h] Print out list of commandline options\n", " [-longhelp] Print out commandline option details\n", " [-version] Print out the build version\n", " [-v #] Verbosity (controls output to console)\n" " 0 = quiet mode\n" " 1 = show average stats (default)\n" " 2 = show each frame's stats\n", " [-threads #] Number of parallel threads to use\n" " 0 = detect number of CPUs (default)\n", " [-nosimd X] Comma-separated list of SIMD instruction sets not to use\n" " Available sets are mmx, sse, sse2, sse3 and altivec.\n" " No spaces are allowed between the sets and the commas.\n", " [-b #] CBR bitrate in kbps (default: about 96kbps per channel)\n", " [-q #] VBR quality [0 - 1023] (default: 240)\n", " [-fba #] Fast bit allocation (default: 0)\n" " 0 = more accurate encoding\n" " 1 = faster encoding\n", " [-exps #] Exponent strategy search size (default: 8)\n" " 1 to 32 (lower is faster, higher is better quality)\n", " [-pad #] Start-of-stream padding\n" " 0 = no padding\n" " 1 = 256 samples of padding (default)\n", " [-w #] Bandwidth\n" " 0 to 60 = fixed bandwidth (28\45-99\45 of full bandwidth)\n" " -1 = fixed adaptive bandwidth (default)\n" " -2 = variable adaptive bandwidth\n", " [-wmin #] Minimum bandwidth [0 - 60] (default: 0)\n", " [-wmax #] Maximum bandwidth [0 - 60] (default: 60)\n", " [-m #] Stereo rematrixing\n" " 0 = independent L+R channels\n" " 1 = mid/side rematrixing (default)\n", " [-s #] Block switching\n" " 0 = use only 512-point MDCT (default)\n" " 1 = selectively use 256-point MDCT\n", " [-cmix #] Center mix level\n" " 0 = -3.0 dB (default)\n" " 1 = -4.5 dB\n" " 2 = -6.0 dB\n", " [-smix #] Surround mix level\n" " 0 = -3 dB (default)\n" " 1 = -6 dB\n" " 2 = 0\n", " [-dsur #] Dolby Surround mode\n" " 0 = not indicated (default)\n" " 1 = not Dolby surround encoded\n" " 2 = Dolby surround encoded\n", " [-dnorm #] Dialog normalization [0 - 31] (default: 31)\n", " [-dynrng #] Dynamic Range Compression profile\n" " 0 = Film Light\n" " 1 = Film Standard\n" " 2 = Music Light\n" " 3 = Music Standard\n" " 4 = Speech\n" " 5 = None (default)\n", " [-acmod #] Audio coding mode (overrides wav header)\n" " 0 = 1+1 (Ch1,Ch2)\n" " 1 = 1/0 (C)\n" " 2 = 2/0 (L,R)\n" " 3 = 3/0 (L,R,C)\n" " 4 = 2/1 (L,R,S)\n" " 5 = 3/1 (L,R,C,S)\n" " 6 = 2/2 (L,R,SL,SR)\n" " 7 = 3/2 (L,R,C,SL,SR)\n", " [-lfe #] Specify use of LFE channel (overrides wav header)\n" " 0 = LFE channel is not present\n" " 1 = LFE channel is present\n", " [-chconfig X] Specify channel configuration (overrides wav header)\n" " 1+1 = (Ch1,Ch2)\n" " 1/0 = (C)\n" " 2/0 = (L,R)\n" " 3/0 = (L,R,C)\n" " 2/1 = (L,R,S)\n" " 3/1 = (L,R,C,S)\n" " 2/2 = (L,R,SL,SR)\n" " 3/2 = (L,R,C,SL,SR)\n" " adding \"+LFE\" indicates use of the LFE channel\n", " [-ch_X file] Add a mono file to the input list as the channel specified\n" " ch_fl = Front Left\n" " ch_fc = Front Center\n" " ch_fr = Front Right\n" " ch_sl = Surround Left\n" " ch_s = Surround\n" " ch_sr = Surround Right\n" " ch_m1 = Dual Mono Channel 1\n" " ch_m2 = Dual Mono Channel 2\n" " ch_lfe = LFE\n", " [-raw_fmt X] Raw audio input sample format (default: s16_le)\n" " One of the pre-defined sample formats:\n" " u8, s8, s16_le, s16_be, s20_le, s20_be, s24_le, s24_be,\n" " s32_le, s32_be, float_le, float_be, double_le, double_be\n", " [-raw_sr #] Raw audio input sample rate (default: 48000)\n", " [-raw_ch #] Raw audio input channels (default: 1)\n", " [-chmap #] Channel mapping order of input audio\n" " 0 = WAVE mapping (default)\n" " 1 = AC-3 mapping\n" " 2 = MPEG mapping\n", " [-readtoeof #] Read input WAVE audio data until the end-of-file\n" " 0 = use data size in header (default)\n" " 1 = read data until end-of-file\n", " [-bwfilter #] Specify use of the bandwidth low-pass filter\n" " 0 = do not apply filter (default)\n" " 1 = apply filter\n", " [-dcfilter #] Specify use of the DC high-pass filter\n" " 0 = do not apply filter (default)\n" " 1 = apply filter\n", " [-lfefilter #] Specify use of the LFE low-pass filter\n" " 0 = do not apply filter (default)\n" " 1 = apply filter\n", " [-xbsi1 #] Specify use of extended bitstream info 1\n" " 0 = do not write xbsi1\n" " 1 = write xbsi1\n", " [-dmixmod #] Preferred stereo downmix mode\n" " 0 = not indicated (default)\n" " 1 = Lt/Rt downmix preferred\n" " 2 = Lo/Ro downmix preferred\n", " [-ltrtcmix #] Lt/Rt center mix level\n", " [-ltrtsmix #] Lt/Rt surround mix level\n", " [-lorocmix #] Lo/Ro center mix level\n", " [-lorosmix #] Lo/Ro surround mix level\n" " 0 = +3.0 dB\n" " 1 = +1.5 dB\n" " 2 = 0.0 dB\n" " 3 = -1.5 dB\n" " 4 = -3.0 dB (default)\n" " 5 = -4.5 dB\n" " 6 = -6.0 dB\n" " 7 = -inf dB\n", " [-xbsi2 #] Specify use of extended bitstream info 2\n" " 0 = do not write xbsi2\n" " 1 = write xbsi2\n", " [-dsurexmod #] Dolby Surround EX mode\n" " 0 = not indicated (default)\n" " 1 = Not Dolby Surround EX encoded\n" " 2 = Dolby Surround EX encoded\n", " [-dheadphon #] Dolby Headphone mode\n" " 0 = not indicated (default)\n" " 1 = Not Dolby Headphone encoded\n" " 2 = Dolby Headphone encoded\n", " [-adconvtyp #] A/D converter type\n" " 0 = Standard (default)\n" " 1 = HDCD\n" }; /* longhelp string constants */ #define CONSOLE_OPTIONS_COUNT 4 static const char console_heading[24] = "CONSOLE OUTPUT OPTIONS\n"; static const char *console_options[CONSOLE_OPTIONS_COUNT] = { " [-h] Print out list of commandline options.\n", " [-longhelp] Print out commandline option details.\n", " [-version] Print out the build version.\n", " [-v #] Verbosity\n" " This controls the level of console output to stderr.\n" " 0 - Quiet Mode. No output to stderr.\n" " 1 - Shows a running average of encoding statistics.\n" " This is the default setting.\n" " 2 - Shows the statistics for each frame.\n" }; #define ENCODING_OPTIONS_COUNT 12 static const char encoding_heading[18] = "ENCODING OPTIONS\n"; static const char *encoding_options[ENCODING_OPTIONS_COUNT] = { " [-threads #] Number of threads\n" " Aften can use multiple threads to speed up encoding.\n" " By default, Aften uses one thread for each logical CPU\n" " your system has, but you can override this value. A\n" " value of 0 is the default and indicates that Aften\n" " should try to detect the number of CPUs.\n", " [-nosimd X] Comma-separated list of SIMD instruction sets not to use\n" " Aften will auto-detect available SIMD instruction sets\n" " for your CPU, so you shouldn't need to disable sets\n" " explicitly - unless for speed or debugging reasons.\n" " Available sets are mmx, sse, sse2, sse3 and altivec.\n" " No spaces are allowed between the sets and the commas.\n" " Example: -nosimd sse2,sse3\n", " [-b #] CBR bitrate in kbps\n" " CBR mode is selected by default. This option allows for\n" " setting the fixed bitrate. The default bitrate depends\n" " on the number of channels (not including LFE).\n" " mono = 96 kbps\n" " stereo = 192 kbps\n" " 3-channel = 256 kbps\n" " 4-channel = 384 kbps\n" " 5-channel = 448 kbps\n", " [-q #] VBR quality\n" " A value 0 to 1023 which corresponds to SNR offset, where\n" " q=240 equates to an SNR offset of 0. 240 is the default\n" " value. This scale will most likely be replaced in the\n" " future with a better quality measurement.\n", " [-fba #] Fast bit allocation\n" " Fast bit allocation is a less-accurate search method\n" " for CBR bit allocation. It only narrows down the SNR\n" " value to within 16 of the optimal value. The result\n" " is lower overall quality, but faster encoding. This\n" " may not give the same results each time when using\n" " parallel encoding.\n", " [-exps #] Exponent strategy search size\n" " The encoder determines the best combination of\n" " exponent strategies for a frame by searching through\n" " a list of pre-defined exponent strategies. This option\n" " controls the size of the list to be searched. The\n" " value can range from 1 (lower quality but faster) to\n" " 32 (higher quality but slower). The default value is 8.\n", " [-pad #] Start-of-stream padding\n" " The AC-3 format uses an overlap/add cycle for encoding\n" " each block. By default, Aften pads the delay buffer\n" " with a block of silence to avoid inaccurate encoding\n" " of the first frame of audio. If this behavior is not\n" " wanted, it can be disabled. The pad value can be a\n" " 1 (default) to use padding or 0 to not use padding.\n", " [-w #] Bandwidth\n" " The bandwidth setting corresponds to the high-frequency\n" " cutoff. Specifically, it sets the highest frequency bin\n" " which is encoded. The AC-3 format uses a 512-point MDCT\n" " which gives 256 frequency levels from 0 to 1/2 of the\n" " samplerate. The formula to give the number of coded\n" " frequency bins from bandwidth setting is:\n" " (w * 3) + 73, which gives a range of 73 to 253\n" " I hope to replace this setting with one where the user\n" " specifies the actual cutoff frequency rather than the\n" " bandwidth code.\n" " There are 2 special values, -1 and -2.\n" " When -1 is used, Aften automatically selects what\n" " it thinks is an appropriate bandwidth. This is the\n" " default setting.\n" " When -2 is used, a bandwidth is chosen for each frame\n" " based on CBR frame size and a target quality of 240.\n" " Variable bandwidth cannot be used with VBR mode.\n", " [-wmin #] Minimum bandwidth\n" " For variable bandwidth mode (-2), this option sets the\n" " minimum value for the bandwidth code. This allows the\n" " user to avoid a harsh cutoff frequency by sacrificing\n" " general audio quality. The default value is 0.\n", " [-wmax #] Maximum bandwidth\n" " For variable bandwidth mode (-2), this option sets the\n" " maximum value for the bandwidth code. This can be used\n" " to speed up encoding by using a lower value than 60,\n" " which is the default.\n", " [-m #] Stereo rematrixing\n" " Using stereo rematrixing can increase quality by\n" " removing redundant information between the left and\n" " right channels. This technique is common in audio\n" " encoding, and is sometimes called mid/side encoding.\n" " When this setting is turned on, Aften adaptively turns\n" " rematrixing on or off for each of 4 frequency bands for\n" " each block. When this setting is turned off,\n" " rematrixing is not used for any blocks. The default\n" " value is 1.\n", " [-s #] Block switching\n" " The AC-3 format allows for 2 different types of MDCT\n" " transformations to translate from time-domain to\n" " frequency-domain. The default is a 512-point transform,\n" " which gives better frequency resolution. There is also\n" " a 256-point transform, which gives better time\n" " resolution. The specification gives a suggested method\n" " for determining when to use the 256-point transform.\n" " When block switching is turned on, Aften uses the spec\n" " method for selecting the 256-point MDCT. When it is\n" " turned off, only the 512-point MDCT is used, which is\n" " faster. Block switching is turned off by default.\n", }; #define BSI_OPTIONS_COUNT 3 static const char bsi_heading[25] = "BITSTREAM INFO METADATA\n"; static const char *bsi_options[BSI_OPTIONS_COUNT] = { " [-cmix #] Center mix level\n" " When three front channels are in use, this code\n" " indicates the nominal down mix level of the center\n" " channel with respect to the left and right channels.\n" " 0 = -3.0 dB (default)\n" " 1 = -4.5 dB\n" " 2 = -6.0 dB\n", " [-smix #] Surround mix level\n" " If surround channels are in use, this code indicates\n" " the nominal down mix level of the surround channels.\n" " 0 = -3 dB (default)\n" " 1 = -6 dB\n" " 2 = 0\n", " [-dsur #] Dolby Surround mode\n" " When operating in the two channel mode, this code\n" " indicates whether or not the program has been encoded in\n" " Dolby Surround. This information is not used by the\n" " AC-3 decoder, but may be used by other portions of the\n" " audio reproduction equipment.\n" " 0 = not indicated (default)\n" " 1 = not Dolby surround encoded\n" " 2 = Dolby surround encoded\n" }; #define DRC_OPTIONS_COUNT 2 static const char drc_heading[52] = "DYNAMIC RANGE COMPRESSION AND DIALOG NORMALIZATION\n"; static const char *drc_options[DRC_OPTIONS_COUNT] = { " [-dynrng #] Dynamic Range Compression profile\n" " Dynamic Range Compression allows for the final output\n" " dynamic range to be limited without sacrificing quality.\n" " The full dynamic range audio is still encoded, but a\n" " code is given for each block which tells the decoder to\n" " adjust the output volume for that block. The encoder\n" " must analyze the input audio to determine the best way\n" " to compress the dynamic range based on the loudness and\n" " type of input (film, music, speech).\n" " 0 = Film Light\n" " 1 = Film Standard\n" " 2 = Music Light\n" " 3 = Music Standard\n" " 4 = Speech\n" " 5 = None (default)\n", " [-dnorm #] Dialog normalization [0 - 31] (default: 31)\n" " The dialog normalization value sets the average dialog\n" " level. The value is typically constant for a particular\n" " audio program. The decoder has a target output dialog\n" " level of -31dB, so if the dialog level is specified as\n" " being -31dB already (default), the output volume is not\n" " altered. Otherwise, the overall output volume is\n" " decreased so that the dialog level is adjusted down to\n" " -31dB.\n" }; #define INPUT_OPTIONS_COUNT 10 static const char input_heading[17] = "INPUT OPTIONS\n"; static const char *input_options[INPUT_OPTIONS_COUNT] = { " By default, information about the input file, such as the channel\n" " configuration and data size, is determined by the input file wav header.\n" " However, the basic WAVE format is limited in that it can only support\n" " up to 4 GB of data and cannot specify all channel layouts possible in the\n" " AC-3 format. The acmod, lfe, and chconfig options allow the user to\n" " explicitly select the desired channel layout. This only controls the\n" " interpretation of the input, so no downmixing or upmixing is done. The\n" " readtoeof option overrides the header and lets the user specify that Aften\n" " should keep reading data until the end-of-file.\n", " [-acmod #] Audio coding mode (overrides wav header)\n" " 0 = 1+1 (Ch1,Ch2)\n" " 1 = 1/0 (C)\n" " 2 = 2/0 (L,R)\n" " 3 = 3/0 (L,R,C)\n" " 4 = 2/1 (L,R,S)\n" " 5 = 3/1 (L,R,C,S)\n" " 6 = 2/2 (L,R,SL,SR)\n" " 7 = 3/2 (L,R,C,SL,SR)\n", " [-lfe #] Specify use of LFE channel (overrides wav header)\n" " 0 = LFE channel is not present\n" " 1 = LFE channel is present\n", " [-chconfig X] Specify channel configuration (overrides wav header)\n" " 1+1 = (Ch1,Ch2)\n" " 1/0 = (C)\n" " 2/0 = (L,R)\n" " 3/0 = (L,R,C)\n" " 2/1 = (L,R,S)\n" " 3/1 = (L,R,C,S)\n" " 2/2 = (L,R,SL,SR)\n" " 3/2 = (L,R,C,SL,SR)\n" " adding \"+LFE\" indicates use of the LFE channel\n", " [-ch_X file] Add a mono file to the input list as the channel specified\n" " These parameters are used to specify multiple mono\n" " source files instead of a single multi-channel source\n" " file. Only valid AC-3 combinations are allowed. The\n" " acmod, lfe, chconfig, and chmap parameters are all\n" " ignored if multi-mono inputs are used.\n" " ch_fl = Front Left\n" " ch_fc = Front Center\n" " ch_fr = Front Right\n" " ch_sl = Surround Left\n" " ch_s = Surround\n" " ch_sr = Surround Right\n" " ch_m1 = Dual Mono Channel 1\n" " ch_m2 = Dual Mono Channel 2\n" " ch_lfe = LFE\n", " [-raw_fmt X] Raw audio input sample format (default: s16_le)\n" " This options specifies the sample format when using\n" " raw audio input. Using this option forces Aften to\n" " treat the input as raw audio. The choices for the\n" " pre-defined sample formats are:\n" " u8, s8, s16_le, s16_be, s20_le, s20_be, s24_le, s24_be,\n" " s32_le, s32_be, float_le, float_be, double_le, double_be\n", " [-raw_sr #] Raw audio input sample rate (default: 48000)\n" " Using this option forces Aften to treat the input as\n" " raw audio.\n", " [-raw_ch #] Raw audio input channels (default: 1)\n" " Using this option forces Aften to treat the input as\n" " raw audio.\n", " [-chmap #] Channel mapping order of input audio\n" " Some programs create WAVE files which use a channel\n" " mapping other than the standard WAVE mapping. This\n" " option allows the user to specify if the input file\n" " uses WAVE, AC-3, or MPEG channel mapping. The MPEG\n" " channel mapping is used by DTS and by MPEG-2/4 formats\n" " such as MP2 and AAC.\n" " 0 = WAVE mapping (default)\n" " 1 = AC-3 mapping\n" " 2 = MPEG mapping\n", " [-readtoeof #] Read input WAVE audio data until the end-of-file.\n" " This overrides the data size in the WAVE header, and\n" " can be useful for streaming input or files larger than\n" " 4 GB.\n" " 0 = use data size in header (default)\n" " 1 = read data until end-of-file\n" }; #define FILTER_OPTIONS_COUNT 3 static const char filter_heading[15] = "INPUT FILTERS\n"; static const char *filter_options[FILTER_OPTIONS_COUNT] = { " [-bwfilter #] Specify use of the bandwidth low-pass filter\n" " The bandwidth low-pass filter pre-filters the input\n" " audio before converting to frequency-domain. This\n" " smooths the cutoff frequency transition for slightly\n" " better quality. When used with variable bandwidth\n" " mode, the maximum bandwidth setting used as the cutoff\n" " frequency.\n" " 0 = do not apply filter (default)\n" " 1 = apply filter\n", " [-dcfilter #] Specify use of the DC high-pass filter\n" " The DC high-pass filter is listed as optional by the\n" " AC-3 specification. The implementation, as suggested,\n" " is a single pole filter at 3 Hz.\n" " 0 = do not apply filter (default)\n" " 1 = apply filter\n", " [-lfefilter #] Specify use of the LFE low-pass filter\n" " The LFE low-pass filter is recommended by the AC-3\n" " specification. The cutoff is 120 Hz. The specification\n" " recommends an 8th order elliptic filter, but instead,\n" " Aften uses a Butterworth 2nd order cascaded direct\n" " form II filter.\n" " 0 = do not apply filter (default)\n" " 1 = apply filter\n" }; #define ALT_OPTIONS_COUNT 12 static const char alt_heading[29] = "ALTERNATE BIT STREAM SYNTAX\n"; static const char *alt_options[ALT_OPTIONS_COUNT] = { " The alternate bit stream syntax allows for encoding additional metadata by\n" " adding 1 or 2 extended bitstream info sections to each frame.\n", " [-xbsi1 #] Specify use of extended bitstream info 1\n" " Extended bitstream info 1 contains the dmixmod,\n" " ltrtcmix, ltrtsmix, lorocmix, and lorosmix fields. If\n" " this option is turned on, all these values are written\n" " to the output stream.\n" " 0 = do not write xbsi1\n" " 1 = write xbsi1\n", " [-dmixmod #] Preferred stereo downmix mode\n" " This code indicates the type of stereo downmix preferred\n" " by the mastering engineer, and can be optionally used,\n" " overridden, or ignored by the decoder.\n" " 0 = not indicated (default)\n" " 1 = Lt/Rt downmix preferred\n" " 2 = Lo/Ro downmix preferred\n", " The 4 mix level options below all use the same code table:\n" " 0 = +3.0 dB\n" " 1 = +1.5 dB\n" " 2 = 0.0 dB\n" " 3 = -1.5 dB\n" " 4 = -3.0 dB (default)\n" " 5 = -4.5 dB\n" " 6 = -6.0 dB\n" " 7 = -inf dB\n", " [-ltrtcmix #] Lt/Rt center mix level\n" " This code indicates the nominal down mix level of the\n" " center channel with respect to the left and right\n" " channels in an Lt/Rt downmix.\n", " [-ltrtsmix #] Lt/Rt surround mix level\n" " This code indicates the nominal down mix level of the\n" " surround channels with respect to the left and right\n" " channels in an Lt/Rt downmix.\n", " [-lorocmix #] Lo/Ro center mix level\n" " This code indicates the nominal down mix level of the\n" " center channel with respect to the left and right\n" " channels in an Lo/Ro downmix.\n", " [-lorosmix #] Lo/Ro surround mix level\n" " This code indicates the nominal down mix level of the\n" " surround channels with respect to the left and right\n" " channels in an Lo/Ro downmix.\n", " [-xbsi2 #] Specify use of extended bitstream info 2\n" " Extended bitstream info 2 contains the dsurexmod,\n" " dheadphon, and adconvtyp fields. If this option is\n" " turned on, all these values are written to the output\n" " stream. These options are not used by the AC-3 decoder,\n" " but may be used by other portions of the audio\n" " reproduction equipment.\n" " 0 = do not write xbsi2\n" " 1 = write xbsi2\n", " [-dsurexmod #] Dolby Surround EX mode\n" " This code indicates whether or not the program has been\n" " encoded in Dolby Surround EX.\n" " 0 = not indicated (default)\n" " 1 = Not Dolby Surround EX encoded\n" " 2 = Dolby Surround EX encoded\n", " [-dheadphon #] Dolby Headphone mode\n" " This code indicates whether or not the program has been\n" " Dolby Headphone-encoded.\n" " 0 = not indicated (default)\n" " 1 = Not Dolby Headphone encoded\n" " 2 = Dolby Headphone encoded\n", " [-adconvtyp #] A/D converter type\n" " This code indicates the type of A/D converter technology\n" " used to capture the PCM audio.\n" " 0 = Standard (default)\n" " 1 = HDCD\n" }; typedef struct { int section_count; const char *section_heading; const char **section_options; } LongHelpSection; #define LONG_HELP_SECTIONS_COUNT 7 static const LongHelpSection long_help_sections[LONG_HELP_SECTIONS_COUNT] = { { CONSOLE_OPTIONS_COUNT, console_heading, console_options }, { ENCODING_OPTIONS_COUNT, encoding_heading, encoding_options }, { BSI_OPTIONS_COUNT, bsi_heading, bsi_options }, { DRC_OPTIONS_COUNT, drc_heading, drc_options }, { INPUT_OPTIONS_COUNT, input_heading, input_options }, { FILTER_OPTIONS_COUNT, filter_heading, filter_options }, { ALT_OPTIONS_COUNT, alt_heading, alt_options } }; static void print_usage(FILE *out) { fprintf(out, "%s", usage_heading); fprintf(out, "type 'aften -h' for more details.\n\n"); } static void print_long_help(FILE *out) { int i, j; fprintf(out, "%s", usage_heading); fprintf(out, "options:\n\n"); for (i = 0; i < LONG_HELP_SECTIONS_COUNT; i++) { fprintf(out, "%s\n", long_help_sections[i].section_heading); for (j = 0; j < long_help_sections[i].section_count; j++) { fprintf(out, "%s\n", long_help_sections[i].section_options[j]); } } } static void print_help(FILE *out) { int i; fprintf(out, "%s", usage_heading); fprintf(out, "options:\n"); for (i = 0; i < HELP_OPTIONS_COUNT; i++) { fprintf(out, "%s", help_options[i]); } fprintf(out, "\n"); } #endif /* HELPTEXT_H */ aften/aften/opts.c000066400000000000000000000473341132016273200144110ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * Copyright (c) 2007 Justin Ruggles * 2007 Prakash Punnoor * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file opts.c * Commandline options */ #include "common.h" #include #include #include #include #include "opts.h" #include "pcm.h" typedef struct PrivateOptions { int found_output; int single_input; int multi_input; int empty_params; int input_mask; int arg_index; } PrivateOptions; #define OPTION_FLAGS_NONE 0x0 #define OPTION_FLAG_NO_PARAM 0x1 #define OPTION_FLAG_MATCH_PARTIAL 0x2 struct OptionItem; #define PARSE_PARAMS UNUSED(char *arg), UNUSED(char *param), \ UNUSED(const struct OptionItem *item), \ UNUSED(CommandOptions *opts), UNUSED(PrivateOptions *priv) typedef struct OptionItem { const char *option_str; int flags; int min; int max; int (*parse)(PARSE_PARAMS); int offset; } OptionItem; static inline int parse_integer_value(int val, int min, int max, char *name, int *out) { if (val < min || val > max) { fprintf(stderr, "invalid parameter -%s %d. must be %d to %d.\n", name, val, min, max); return 1; } *out = val; return 0; } static int parse_bool_or_int(const char *param, int *val) { if (!strncmp(param, "no", 3) || !strncmp(param, "off", 4)) { *val = 0; return 0; } else if (!strncmp(param, "yes", 4) || !strncmp(param, "on", 3)) { *val = 1; return 0; } else { char *endp; int v = strtol(param, &endp, 0); if (*endp) return -1; *val = v; return 0; } } static int parse_simple_int_s(PARSE_PARAMS) { int v=0; if (parse_bool_or_int(param, &v)) { fprintf(stderr, "invalid integer or boolean value: %s\n", param); return 1; } return parse_integer_value(v, item->min, item->max, arg, (int *)(((uint8_t *)opts->s) + item->offset)); } static int parse_simple_int_o(PARSE_PARAMS) { int v=0; if (parse_bool_or_int(param, &v)) { fprintf(stderr, "invalid integer or boolean value: %s\n", param); return 1; } return parse_integer_value(v, item->min, item->max, arg, (int *)(((uint8_t *)opts) + item->offset)); } static int parse_h(PARSE_PARAMS) { return 2; } static int parse_longhelp(PARSE_PARAMS) { return 3; } static int parse_version(PARSE_PARAMS) { return 4; } static int parse_nosimd(PARSE_PARAMS) { int i, j; int last = 0; char *simd = param; AftenSimdInstructions *wanted_simd_instructions = &opts->s->system.wanted_simd_instructions; for (i = 0; simd[i]; i = j+1) { for (j = i; simd[j] != ','; ++j) { if (!simd[j]) { last = 1; break; } } simd[j] = 0; if (!strncmp(&simd[i], "mmx", 4)) wanted_simd_instructions->mmx = 0; else if (!strncmp(&simd[i], "sse", 4)) wanted_simd_instructions->sse = 0; else if (!strncmp(&simd[i], "sse2", 5)) wanted_simd_instructions->sse2 = 0; else if (!strncmp(&simd[i], "sse3", 5)) wanted_simd_instructions->sse3 = 0; else if (!strncmp(&simd[i], "altivec", 8)) wanted_simd_instructions->altivec = 0; else { fprintf(stderr, "invalid simd instruction set: %s. must be mmx, sse, sse2, sse3 or altivec.\n", &simd[i]); return 1; } if (last) break; } return 0; } static int parse_q(PARSE_PARAMS) { opts->s->params.encoding_mode = AFTEN_ENC_MODE_VBR; return parse_integer_value(atoi(param), item->min, item->max, arg, &opts->s->params.quality); } static int parse_chconfig(PARSE_PARAMS) { if (!strncmp(param, "1+1", 4)) { opts->s->acmod = 0; } else if (strlen(param) >= 3 && param[1] == '/') { int front_ch = param[0] - '0'; int rear_ch = param[2] - '0'; if (front_ch > 3 || front_ch < 1 || rear_ch < 0 || rear_ch > 2 || (front_ch < 2 && rear_ch != 0)) goto invalid_config; opts->s->acmod = front_ch + 2 * rear_ch; } else { invalid_config: fprintf(stderr, "invalid chconfig: %s\n", param); return 1; } if (!strncmp(¶m[3], "+LFE", 5) || !strncmp(¶m[3], "+lfe", 5)) { opts->s->lfe = 1; } return 0; } /** * Channel bitmask values * Note that the bitmask used here is not the same as the WAVE channel mask. * They are arranged so that any valid channel combination will be in proper * AC3 channel order. */ #define CHMASK_FL 0x1 #define CHMASK_FC 0x2 #define CHMASK_FR 0x4 #define CHMASK_SL 0x8 #define CHMASK_S 0x10 #define CHMASK_SR 0x20 #define CHMASK_M1 0x40 #define CHMASK_M2 0x80 #define CHMASK_LFE 0x100 static int validate_input_files(char **infile, int input_mask, int *acmod, int *lfe) { int i, j, l; // check for valid configurations l = !!(input_mask & CHMASK_LFE); input_mask &= 0xFF; switch (input_mask) { case (CHMASK_M1 | CHMASK_M2): *acmod = 0; break; case (CHMASK_FC): *acmod = 1; break; case (CHMASK_FL | CHMASK_FR): *acmod = 2; break; case (CHMASK_FL | CHMASK_FC | CHMASK_FR): *acmod = 3; break; case (CHMASK_FL | CHMASK_FR | CHMASK_S): *acmod = 4; break; case (CHMASK_FL | CHMASK_FC | CHMASK_FR | CHMASK_S): *acmod = 5; break; case (CHMASK_FL | CHMASK_FR | CHMASK_SL | CHMASK_SR): *acmod = 6; break; case (CHMASK_FL | CHMASK_FC | CHMASK_FR | CHMASK_SL | CHMASK_SR): *acmod = 7; break; default: return -1; } *lfe = l; // shift used channels, filling NULL gaps in infile array for (i = 1; i < A52_NUM_SPEAKERS; i++) { for (j = i; j > 0 && infile[j] != NULL && infile[j-1] == NULL; j--) { infile[j-1] = infile[j]; infile[j] = NULL; } } return 0; } static int parse_ch(PARSE_PARAMS) { static const char chstrs[A52_NUM_SPEAKERS][4] = { "fl", "fc", "fr", "sl", "s", "sr", "m1", "m2", "lfe" }; char *chstr = &arg[3]; int n_chstr, mask_bit; if (priv->single_input) { fprintf(stderr, "cannot mix single-input syntax and multi-input syntax\n"); return 1; } mask_bit = 1; for (n_chstr=0; n_chstrinput_mask & mask_bit) { fprintf(stderr, "invalid input channel parameter\n"); return 1; } priv->input_mask |= mask_bit; opts->infile[n_chstr] = param; } mask_bit += mask_bit; } priv->multi_input = 1; opts->num_input_files++; return 0; } static int parse_raw_fmt(PARSE_PARAMS) { static const char *raw_fmt_strs[8] = { "u8", "s8", "s16_", "s20_", "s24_", "s32_", "float_", "double_" }; enum PcmSampleFormat j; // parse format for (j = PCM_SAMPLE_FMT_U8; j <= PCM_SAMPLE_FMT_DBL; j++) { if (!strncmp(param, raw_fmt_strs[j], strlen(raw_fmt_strs[j]))) { opts->raw_fmt = j; break; } } if (j > PCM_SAMPLE_FMT_DBL) { fprintf(stderr, "invalid raw_fmt: %s\n", param); return 1; } // parse byte order opts->raw_order = PCM_BYTE_ORDER_LE; if (strncmp(param, "u8", 3) && strncmp(param, "s8", 3)) { if (!strncmp(¶m[4], "be", 3)) { opts->raw_order = PCM_BYTE_ORDER_BE; } else if (strncmp(¶m[4], "le", 3)) { fprintf(stderr, "invalid raw_fmt: %s\n", param); return 1; } } opts->raw_input = 1; return 0; } static int parse_raw_option(PARSE_PARAMS) { opts->raw_input = 1; return parse_simple_int_o(arg, param, item, opts, priv); } static int parse_xbsi1_opt(PARSE_PARAMS) { opts->s->meta.xbsi1e = 1; return parse_simple_int_s(arg, param, item, opts, priv); } static int parse_xbsi2_opt(PARSE_PARAMS) { opts->s->meta.xbsi2e = 1; return parse_simple_int_s(arg, param, item, opts, priv); } #define OPTION_ITEM_COUNT 43 /** * list of commandline options, in alphabetical order. */ static const OptionItem options_list[OPTION_ITEM_COUNT] = { // NAME FLAGS MIN MAX PARSE FUNCTION OFFSET // ------ ------- ----- ----- ---------------- -------- { "acmod", OPTION_FLAGS_NONE, 0, 7, parse_simple_int_s, offsetof(AftenContext, acmod) }, { "adconvtyp", OPTION_FLAGS_NONE, 0, 1, parse_simple_int_s, offsetof(AftenContext, meta.adconvtyp) }, { "b", OPTION_FLAGS_NONE, 0, 640, parse_simple_int_s, offsetof(AftenContext, params.bitrate) }, { "bwfilter", OPTION_FLAGS_NONE, 0, 1, parse_simple_int_s, offsetof(AftenContext, params.use_bw_filter) }, { "ch_", OPTION_FLAG_MATCH_PARTIAL, 0, 0, parse_ch, 0 }, { "chconfig", OPTION_FLAGS_NONE, 0, 0, parse_chconfig, 0 }, { "chmap", OPTION_FLAGS_NONE, 0, 2, parse_simple_int_o, offsetof(CommandOptions, chmap) }, { "cmix", OPTION_FLAGS_NONE, 0, 2, parse_simple_int_s, offsetof(AftenContext, meta.cmixlev) }, { "dcfilter", OPTION_FLAGS_NONE, 0, 1, parse_simple_int_s, offsetof(AftenContext, params.use_dc_filter) }, { "dheadphon", OPTION_FLAGS_NONE, 0, 2, parse_xbsi2_opt, offsetof(AftenContext, meta.dheadphonmod) }, { "dmixmod", OPTION_FLAGS_NONE, 0, 2, parse_xbsi1_opt, offsetof(AftenContext, meta.dmixmod) }, { "dnorm", OPTION_FLAGS_NONE, 0, 31, parse_simple_int_s, offsetof(AftenContext, meta.dialnorm) }, { "dsur", OPTION_FLAGS_NONE, 0, 2, parse_simple_int_s, offsetof(AftenContext, meta.dsurmod) }, { "dsurexmod", OPTION_FLAGS_NONE, 0, 2, parse_xbsi2_opt, offsetof(AftenContext, meta.dsurexmod) }, { "dynrng", OPTION_FLAGS_NONE, 0, 5, parse_simple_int_s, offsetof(AftenContext, params.dynrng_profile) }, { "exps", OPTION_FLAGS_NONE, 1, 32, parse_simple_int_s, offsetof(AftenContext, params.expstr_search) }, { "fba", OPTION_FLAGS_NONE, 0, 1, parse_simple_int_s, offsetof(AftenContext, params.bitalloc_fast) }, { "h", OPTION_FLAG_NO_PARAM, 0, 0, parse_h, 0 }, { "lfe", OPTION_FLAGS_NONE, 0, 1, parse_simple_int_s, offsetof(AftenContext, lfe) }, { "lfefilter", OPTION_FLAGS_NONE, 0, 1, parse_simple_int_s, offsetof(AftenContext, params.use_lfe_filter) }, { "longhelp", OPTION_FLAG_NO_PARAM, 0, 0, parse_longhelp, 0 }, { "lorocmix", OPTION_FLAGS_NONE, 0, 7, parse_xbsi1_opt, offsetof(AftenContext, meta.lorocmixlev) }, { "lorosmix", OPTION_FLAGS_NONE, 0, 7, parse_xbsi1_opt, offsetof(AftenContext, meta.lorosmixlev) }, { "ltrtcmix", OPTION_FLAGS_NONE, 0, 7, parse_xbsi1_opt, offsetof(AftenContext, meta.ltrtcmixlev) }, { "ltrtsmix", OPTION_FLAGS_NONE, 0, 7, parse_xbsi1_opt, offsetof(AftenContext, meta.ltrtsmixlev) }, { "m", OPTION_FLAGS_NONE, 0, 1, parse_simple_int_s, offsetof(AftenContext, params.use_rematrixing) }, { "nosimd", OPTION_FLAGS_NONE, 0, 0, parse_nosimd, 0 }, { "pad", OPTION_FLAGS_NONE, 0, 1, parse_simple_int_o, offsetof(CommandOptions, pad_start) }, { "q", OPTION_FLAGS_NONE, 0, 1023, parse_q, 0 }, { "raw_ch", OPTION_FLAGS_NONE, 1, 6, parse_raw_option, offsetof(CommandOptions, raw_ch) }, { "raw_fmt", OPTION_FLAGS_NONE, 0, 0, parse_raw_fmt, 0 }, { "raw_sr", OPTION_FLAGS_NONE, 1, 48000, parse_raw_option, offsetof(CommandOptions, raw_sr) }, { "readtoeof", OPTION_FLAGS_NONE, 0, 1, parse_simple_int_o, offsetof(CommandOptions, read_to_eof) }, { "s", OPTION_FLAGS_NONE, 0, 1, parse_simple_int_s, offsetof(AftenContext, params.use_block_switching) }, { "smix", OPTION_FLAGS_NONE, 0, 2, parse_simple_int_s, offsetof(AftenContext, meta.surmixlev) }, { "threads", OPTION_FLAGS_NONE, 0,MAX_NUM_THREADS, parse_simple_int_s, offsetof(AftenContext, system.n_threads) }, { "v", OPTION_FLAGS_NONE, 0, 2, parse_simple_int_s, offsetof(AftenContext, verbose) }, { "version", OPTION_FLAG_NO_PARAM, 0, 0, parse_version, 0 }, { "w", OPTION_FLAGS_NONE, -2, 60, parse_simple_int_s, offsetof(AftenContext, params.bwcode) }, { "wmax", OPTION_FLAGS_NONE, 0, 60, parse_simple_int_s, offsetof(AftenContext, params.max_bwcode) }, { "wmin", OPTION_FLAGS_NONE, 0, 60, parse_simple_int_s, offsetof(AftenContext, params.min_bwcode) }, { "xbsi1", OPTION_FLAGS_NONE, 0, 1, parse_simple_int_s, offsetof(AftenContext, meta.xbsi1e) }, { "xbsi2", OPTION_FLAGS_NONE, 0, 1, parse_simple_int_s, offsetof(AftenContext, meta.xbsi2e) }, }; int parse_commandline(int argc, char **argv, CommandOptions *opts) { int i; PrivateOptions priv; if (argc < 2) { return 1; } memset(&priv, 0, sizeof(PrivateOptions)); opts->chmap = 0; opts->num_input_files = 0; memset(opts->infile, 0, A52_NUM_SPEAKERS * sizeof(char *)); opts->outfile = NULL; opts->pad_start = 1; opts->read_to_eof = 0; opts->raw_input = 0; opts->raw_fmt = PCM_SAMPLE_FMT_S16; opts->raw_order = PCM_BYTE_ORDER_LE; opts->raw_sr = 48000; opts->raw_ch = 1; for (priv.arg_index = 1; priv.arg_index < argc; priv.arg_index++) { if (argv[priv.arg_index][0] == '-' && argv[priv.arg_index][1] != '\0') { int j; for (j = 0; j < OPTION_ITEM_COUNT; j++) { char *arg = &argv[priv.arg_index][1]; const OptionItem *item = &options_list[j]; int mc = strlen(item->option_str) + 1; if (item->flags & OPTION_FLAG_MATCH_PARTIAL) mc--; if (!strncmp(arg, item->option_str, mc)) { int ret; char *param = NULL; if (!(item->flags & OPTION_FLAG_NO_PARAM)) { priv.arg_index++; if (priv.arg_index >= argc) return 1; param = argv[priv.arg_index]; } ret = item->parse(arg, param, item, opts, &priv); if (ret) return ret; break; } } if (j >= OPTION_ITEM_COUNT) { fprintf(stderr, "invalid option: %s\n", argv[priv.arg_index]); return 1; } } else { // empty parameter can be single input file or output file if (priv.arg_index >= argc) return 1; priv.empty_params++; if (priv.empty_params == 1) { opts->outfile = argv[priv.arg_index]; priv.found_output = 1; } else if (priv.empty_params == 2) { if (priv.multi_input) { fprintf(stderr, "cannot mix single-input syntax and multi-input syntax\n"); return 1; } priv.single_input = 1; opts->infile[0] = opts->outfile; opts->outfile = argv[priv.arg_index]; opts->num_input_files = 1; } else { fprintf(stderr, "too many empty parameters\n"); return 1; } } } // check that proper input file syntax is used if (!(priv.single_input ^ priv.multi_input)) { fprintf(stderr, "cannot mix single-input syntax and multi-input syntax\n"); return 1; } // check that the number of input files is valid if (opts->num_input_files < 1 || opts->num_input_files > 6) { fprintf(stderr, "invalid number of input channels. must be 1 to 6.\n"); return 1; } // check that an output file has been specified if (!priv.found_output) { fprintf(stderr, "no output file specified.\n"); return 1; } // check the channel configuration if (priv.multi_input) { if (validate_input_files(opts->infile, priv.input_mask, &opts->s->acmod, &opts->s->lfe)) { fprintf(stderr, "invalid input channel configuration\n"); return 1; } opts->chmap = 1; } // disallow piped input with multiple files if (opts->num_input_files > 1) { for (i = 0; i < opts->num_input_files; i++) { if (!strncmp(opts->infile[i], "-", 2)) { fprintf(stderr, "cannot use piped input with multiple files\n"); return 1; } } } // disallow infile & outfile with same name except with piping for (i = 0; i < opts->num_input_files; i++) { if (strncmp(opts->infile[i], "-", 2) && strncmp(opts->outfile, "-", 2)) { if (!strcmp(opts->infile[i], opts->outfile)) { fprintf(stderr, "output filename cannot match any input filename\n"); return 1; } } } return 0; } aften/aften/opts.h000066400000000000000000000025421132016273200144060ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * Copyright (c) 2007 Justin Ruggles * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file opts.h * Commandline options header */ #ifndef OPTS_H #define OPTS_H #include #include "aften.h" #include "pcm.h" #define A52_NUM_SPEAKERS 9 typedef struct { int chmap; int num_input_files; char *infile[A52_NUM_SPEAKERS]; char *outfile; AftenContext *s; int pad_start; int read_to_eof; int raw_input; enum PcmSampleFormat raw_fmt; int raw_order; int raw_sr; int raw_ch; } CommandOptions; extern int parse_commandline(int argc, char **argv, CommandOptions *opts); #endif /* OPTS_H */ aften/bindings/000077500000000000000000000000001132016273200137455ustar00rootroot00000000000000aften/bindings/aftenxx.cxx000066400000000000000000000101461132016273200161500ustar00rootroot00000000000000/******************************************************************************** * Copyright (C) 2007 by Prakash Punnoor * * prakash@punnoor.de * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * ********************************************************************************/ #include "aftenxx.h" namespace Aften { #include "aften.h" /// Constructor: Initializes the encoder with specified context FrameEncoder::FrameEncoder(AftenContext &context) { m_context = context; int nReturnValue = aften_encode_init(&m_context); if (nReturnValue > 0) throw nReturnValue; } /// Destructor: Deinitalizes the encoder FrameEncoder::~FrameEncoder() { aften_encode_close(&m_context); } /// Encodes PCM samples to an A/52 frame int FrameEncoder::Encode(unsigned char *frameBuffer, const void *samples, int count) { return aften_encode_frame(&m_context, frameBuffer, samples, count); } /// Gets a context with default values AftenContext FrameEncoder::GetDefaultsContext() { AftenContext context; aften_set_defaults(&context); return context; } /// Determines the proper A/52 acmod and lfe parameters based on the /// number of channels and the WAVE_FORMAT_EXTENSIBLE channel mask. If the /// channelMask value has the high bit set to 1 (e.g. 0xFFFFFFFF), then the default /// plain WAVE channel selection is assumed. /// On error, an execption is thrown. On success, the acmod and lfe params are set /// to appropriate values. void Utility::WaveChannelsToAcmod(int channels, unsigned int channelMask, int &acmod, bool &hasLfe) { int nLfe; if (aften_wav_channels_to_acmod(channels, channelMask, &acmod, &nLfe) != 0) throw -1; hasLfe = (nLfe != 0); } /// overload for convenience void Utility::WaveChannelsToAcmod(int channels, unsigned int channelMask, int &acmod, int &hasLfe) { if (aften_wav_channels_to_acmod(channels, channelMask, &acmod, &hasLfe) != 0) throw -1; } /// Takes a channel-interleaved array of audio samples, where the channel order /// is the default Wave order. The samples are rearranged to the proper A/52 /// channel order based on the acmod and lfe parameters. void Utility::RemapWaveToA52(void *samples, int samplesCount, int channels, A52SampleFormat format, int acmod) { aften_remap_wav_to_a52(samples, samplesCount, channels, format, acmod); } /// Takes a channel-interleaved array of audio samples, where the channels are /// in MPEG order. The samples are rearranged to the proper A/52 channel order /// based on the acmod parameter. void Utility::RemapMpegToA52(void *samples, int samplesCount, int channels, A52SampleFormat format, int acmod) { aften_remap_mpeg_to_a52(samples, samplesCount, channels, format, acmod); } const char* Utility::GetVersion() { return aften_get_version(); } /// Tells whether libaften was configured to use floats or doubles FloatType Utility::GetFloatType() { return aften_get_float_type(); } } aften/bindings/aftenxx.h000066400000000000000000000076351132016273200156060ustar00rootroot00000000000000/******************************************************************************** * Copyright (C) 2007 by Prakash Punnoor * * prakash@punnoor.de * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * ********************************************************************************/ namespace Aften { #include "aften-types.h" #if defined(_WIN32) && !defined(_XBOX) #if defined(AFTENXX_BUILD_LIBRARY) #define AFTENXX_API __declspec(dllexport) #else #define AFTENXX_API __declspec(dllimport) #endif #else #if defined(AFTENXX_BUILD_LIBRARY) && defined(HAVE_GCC_VISIBILITY) #define AFTENXX_API __attribute__((visibility("default"))) #else #define AFTENXX_API #endif #endif class AFTENXX_API FrameEncoder { private: AftenContext m_context; public: /// Constructor: Initializes the encoder with specified context FrameEncoder(AftenContext &context); /// Destructor: Deinitalizes the encoder ~FrameEncoder(); /// Encodes PCM samples to an A/52 frame; returns encoded frame size int Encode(unsigned char *frameBuffer, const void *samples, int count); /// Gets a context with default values static AftenContext GetDefaultsContext(); }; class AFTENXX_API Utility { public: /// Determines the proper A/52 acmod and lfe parameters based on the /// number of channels and the WAVE_FORMAT_EXTENSIBLE channel mask. If the /// channelMask value has the high bit set to 1 (e.g. 0xFFFFFFFF), then the default /// plain WAVE channel selection is assumed. /// On error, an execption is thrown. On success, the acmod and lfe params are set /// to appropriate values. static void WaveChannelsToAcmod(int channels, unsigned int channelMask, int &acmod, bool &hasLfe); /// overload for convenience static void WaveChannelsToAcmod(int channels, unsigned int channelMask, int &acmod, int &hasLfe); /// Takes a channel-interleaved array of audio samples, where the channel order /// is the default Wave order. The samples are rearranged to the proper A/52 /// channel order based on the acmod and lfe parameters. static void RemapWaveToA52(void *samples, int samplesCount, int channels, A52SampleFormat format, int acmod); /// Takes a channel-interleaved array of audio samples, where the channels /// are in MPEG order. The samples are rearranged to the proper A/52 /// channel order based on the acmod parameter. static void RemapMpegToA52(void *samples, int samplesCount, int channels, A52SampleFormat format, int acmod); /// Gets the libaften version string. static const char* GetVersion(); /// Tells whether libaften was configured to use floats or doubles static FloatType GetFloatType(); }; #undef AFTENXX_API } aften/bindings/cs/000077500000000000000000000000001132016273200143525ustar00rootroot00000000000000aften/bindings/cs/AftenTypes.cs000066400000000000000000000332621132016273200167710ustar00rootroot00000000000000/******************************************************************************** * Copyright (C) 2007 by Prakash Punnoor * * prakash@punnoor.de * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * ********************************************************************************/ using System; namespace Aften { /// /// Some helpful size constants /// public static class A52Sizes { /// /// Maximum encoded ac3 frame size /// public const int MaximumCodedFrameSize = 3840; /// /// Samples per ac3 frame per channel /// public const int SamplesPerFrame = 1536; } /// /// Aften's mode of operation /// internal enum AftenOperationMode { AFTEN_ENCODE, AFTEN_TRANSCODE } /// /// Aften Encoding Mode /// public enum EncodingMode { /// /// CBR /// Cbr = 0, /// /// VBR /// Vbr } /// /// Floating-Point Data Types /// public enum FloatType { /// /// Double /// Double, /// /// Float /// Float } /// /// Audio Sample Formats /// public enum A52SampleFormat { /// /// Unsigned bytes /// UInt8 = 0, /// /// Signed 16bit Words /// Int16, /// /// Signed 20bit Words /// Int20, /// /// Signed 24bit Words /// Int24, /// /// Signed Doublewords /// Int32, /// /// Single precision floating point, normalized to [-1, 1] /// Float, /// /// Double precision floating point, normalized to [-1, 1] /// Double, /// /// Signed bytes /// Int8 } /// /// Dynamic Range Profiles /// public enum DynamicRangeProfile { /// /// Light dynamic range compression for films /// FilmLight = 0, /// /// Standard dynamic range compression for films /// FilmStandard, /// /// Light dynamic range compression for music /// MusicLight, /// /// Standard dynamic range compression for music /// MusicStandard, /// /// Dynamic range compression for ppeech /// Speech, /// /// No dynamic range compression /// None } /// /// Audio Coding Mode (acmod) options /// public enum AudioCodingMode { /// /// Dual Mono /// DualMono = 0, /// /// Mono /// Mono, /// /// Stereo /// Stereo, /// /// 3 front channels, no rear channels /// Front3Rear0, /// /// 2 front channels, 1 rear channel /// Front2Rear1, /// /// 3 front channels, 1 rear channel /// Front3Rear1, /// /// 2 front channels, 2 rear channels /// Front2Rear2, /// /// 3 front channels, 2 rear channels /// Front3Rear2 } /// /// SIMD instruction sets /// public struct SimdInstructions { /// /// MMX /// public bool Mmx; /// /// SSE /// public bool Sse; /// /// SSE2 /// public bool Sse2; /// /// SSE3 /// public bool Sse3; /// /// SSSE3 /// public bool Ssse3; /// /// AMD 3DNow! /// public bool Amd3Dnow; /// /// AMD 3DNow! Extended /// public bool Amd3Dnowext; /// /// AMD SSE MMX Extensions /// public bool AmdSseMmx; /// /// PowerPC Altivec /// public bool Altivec; } /// /// Performance related parameters /// public struct SystemParameters { /// /// Number of threads /// How many threads should be used. /// Default value is 0, which indicates detecting number of CPUs. /// Maximum value is AFTEN_MAX_THREADS. /// public int ThreadsCount; /// /// Available SIMD instruction sets; shouldn't be modified /// public SimdInstructions AvailableSimdInstructions; /// /// Wanted SIMD instruction sets /// public SimdInstructions WantedSimdInstructions; } /// /// Parameters which affect encoded audio output /// public struct EncodingParameters { /// /// Bitrate selection mode. /// AFTEN_ENC_MODE_CBR : constant bitrate /// AFTEN_ENC_MODE_VBR : variable bitrate /// default is CBR /// public EncodingMode EncodingMode; /// /// Stereo rematrixing option. /// Set to 0 to disable stereo rematrixing, 1 to enable it. /// default is 1 /// public bool UseRematrixing; /// /// Block switching option. /// Set to 0 to disable block switching, 1 to enable it. /// default is 0 /// public bool UseBlockSwitching; /// /// DC high-pass filter option. /// Set to 0 to disable the filter, 1 to enable it. /// default is 0 /// public bool UseDCFilter; /// /// Bandwidth low-pass filter option. /// Set to 0 to disable the, 1 to enable it. /// This option cannot be enabled with variable bandwidth mode (bwcode=-2) /// default is 0 /// public bool UseBandwithFilter; /// /// LFE low-pass filter option. /// Set to 0 to disable the filter, 1 to enable it. /// This limits the LFE bandwidth, and can only be used if the input audio /// has an LFE channel. /// default is 0 /// public bool UseLfeFilter; /// /// Constant bitrate. /// This option sets the bitrate for CBR encoding mode. /// It can also be used to set the maximum bitrate for VBR mode. /// It is specified in kbps. Only certain bitrates are valid: /// 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, /// 160, 192, 224, 256, 320, 384, 448, 512, 576, 640 /// default is 0 /// For CBR mode, this selects bitrate based on the number of channels. /// For VBR mode, this sets the maximum bitrate to 640 kbps. /// public int Bitrate; /// /// VBR Quality. /// This option sets the target quality for VBR encoding mode. /// The range is 0 to 1023 and corresponds to the SNR offset. /// default is 240 /// public int Quality; /// /// Bandwidth code. /// This option determines the cutoff frequency for encoded bandwidth. /// 0 to 60 corresponds to a cutoff of 28.5% to 98.8% of the full bandwidth. /// -1 is used for constant adaptive bandwidth. Aften selects a good value /// based on the quality or bitrate parameters. /// -2 is used for variable adaptive bandwidth. Aften selects a value for /// each frame based on the encoding quality level for that frame. /// default is -1 /// public int BandwidthCode; /// /// Bit Allocation speed/accuracy /// This determines how accurate the bit allocation search method is. /// Set to 0 for better quality /// Set to 1 for faster encoding /// default is 0 /// public bool UseFastBitAllocation; /// /// Exponent Strategy search size /// This determines how many exponent strategy sets to search through /// to find the best combination. /// minimum is 1 (fixed strategy, lower quality, faster encoding) /// maximum is 32 (higher quality, slower encoding) /// default is 8 /// public int ExponentStrategySearchSize; /// /// Dynamic Range Compression profile /// This determines which DRC profile to use. /// Film Light: DYNRNG_PROFILE_FILM_LIGHT /// Film Standard: DYNRNG_PROFILE_FILM_STANDARD /// Music Light: DYNRNG_PROFILE_MUSIC_LIGHT /// Music Standard: DYNRNG_PROFILE_MUSIC_STANDARD /// Speech: DYNRNG_PROFILE_SPEECH, /// None: DYNRNG_PROFILE_NONE /// default is None /// public DynamicRangeProfile DynamicRangeProfile; /// /// Minimum bandwidth code. /// For use with variable bandwidth mode, this option determines the /// minimum value for the bandwidth code. /// default is 0. /// public int MinimumBandwidthCode; /// /// Maximum bandwidth code. /// For use with variable bandwidth mode, this option determines the /// maximum value for the bandwidth code. /// default is 60. /// public int MaximumBandwidthCode; } /// /// Metadata parameters /// See the A/52 specification for details regarding the metadata. /// public struct Metadata { /// /// Center mix level /// public int CenterMixLevel; /// /// Surround mix level /// public int SurroundMixLevel; /// /// Dolby(R) Surround mode /// public int DolbySurroundMode; /// /// Dialog normalization /// public int DialogNormalization; /// /// Extended bit stream info 1 exists /// public bool HasExtendedBitstreamInfo1; /// /// Preferred downmix mode /// public int DownMixMode; /// /// LtRt center mix level /// public int LtRtCenterMixLevel; /// /// LtRt surround mix level /// public int LtRtSurroundMixLevel; /// /// LoRo center mix level /// public int LoRoCenterMixLevel; /// /// LoRo surround mix level /// public int LoRoSurroundMixLevel; /// /// Extended bit stream info 2 exists /// public bool HasExtendedBitstreamInfo2; /// /// Dolby(R) Surround EX mode /// public int DolbySurroundEXMode; /// /// Dolby(R) Headphone mode /// public int DolbyHeadphoneMode; /// /// A/D converter type /// public int ADConverterType; } /// /// Values in this structure are updated by Aften during encoding. /// They give information about the previously encoded frame. /// public struct Status { /// /// Quality /// public int Quality; /// /// BitRate /// public int BitRate; /// /// BandwidthCode /// public int BandwidthCode; } /// /// libaften public encoding context /// public struct EncodingContext { /// /// EncodingParameters /// public EncodingParameters EncodingParameters; /// /// Metadata /// public Metadata Metadata; /// /// Status /// public Status Status; /// /// SystemParameters /// public SystemParameters SystemParameters; /// /// Aften's mode of operation /// internal AftenOperationMode Mode; /// /// Verbosity level. /// 0 is quiet mode. 1 and 2 are more verbose. /// default is 1 /// public int Verbosity; /// /// Total number of channels in the input stream. /// public int Channels; /// /// Audio coding mode (channel configuration). /// There are utility functions to set this if you don't know the proper /// value. /// public AudioCodingMode AudioCodingMode; /// /// Indicates that there is an LFE channel present. /// There are utility functions to set this if you don't know the proper /// value. /// public bool HasLfe; /// /// Audio sample rate in Hz /// public int SampleRate; /// /// Audio sample format /// default: Int16 /// internal A52SampleFormat SampleFormat; #pragma warning disable 0169 /// /// Initial samples /// To prevent padding und thus to get perfect sync, /// exactly 256 samples/channel can be provided here. /// This is not recommended, as without padding these samples can't be properly /// reconstructed anymore. /// private IntPtr InitialSamples; /// /// Used internally by the encoder. The user should leave this alone. /// It is allocated in aften_encode_init and free'd in aften_encode_close. /// private IntPtr m_Context; #pragma warning restore 0169 } } aften/bindings/cs/FrameEncoder.cs000066400000000000000000000607741132016273200172510ustar00rootroot00000000000000/******************************************************************************** * Copyright (C) 2007 by Prakash Punnoor * * prakash@punnoor.de * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * ********************************************************************************/ using System; using System.IO; using System.Runtime.InteropServices; using System.Threading; namespace Aften { #region FrameEncoder base class /// /// The Aften AC3 Encoder base class /// public abstract class FrameEncoder : IDisposable { /// /// Error message EqualAmountOfSamples /// protected const string _EqualAmountOfSamples = "Each channel must have an equal amount of samples."; private readonly int m_nChannels; private bool m_bDisposed; private bool m_bEncodingDone; [DllImport( "aften.dll" )] private static extern void aften_set_defaults( ref EncodingContext context ); [DllImport( "aften.dll" )] protected static extern int aften_encode_init( ref EncodingContext context ); [DllImport( "aften.dll" )] protected static extern void aften_encode_close( ref EncodingContext context ); /// /// Releases unmanaged and - optionally - managed resources /// /// true to release both managed and unmanaged resources; false to release only unmanaged resources. private void Dispose( bool disposing ) { // Check to see if Dispose has already been called. if ( !m_bDisposed ) { if ( disposing ) { // Dispose managed resources } // Release unmanaged resources DoCloseEncoder(); m_bDisposed = true; } } /// /// Gets or sets a value indicating whether encoding is done. /// /// true if encoding is done; otherwise, false. protected bool EncodingDone { get { return m_bEncodingDone; } set { m_bEncodingDone = value; } } /// /// Checks the length of the samples array. /// /// The samples. protected void CheckSamplesLength( Array samples ) { if ( samples.Length % m_nChannels != 0 ) throw new InvalidOperationException( _EqualAmountOfSamples ); } /// /// Closes the encoder. /// protected abstract void DoCloseEncoder(); /// /// Called when a frame has been encoded. /// /// The sender. /// The instance containing the event data. protected virtual void OnFrameEncoded( object sender, FrameEventArgs e ) { if ( FrameEncoded != null ) FrameEncoded( sender, e ); } /// /// Raised when a frame has been encoded. /// public event EventHandler FrameEncoded; /// /// Gets a default context. /// /// public static EncodingContext GetDefaultsContext() { EncodingContext context = new EncodingContext(); aften_set_defaults( ref context ); return context; } /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// public void Dispose() { this.Dispose( true ); GC.SuppressFinalize( this ); } #region Encoding /// /// Encodes the specified interleaved samples. /// /// The samples. /// MemoryStream containing the encoded frames public MemoryStream Encode( Array samples ) { this.CheckSamplesLength( samples ); return this.Encode( samples, samples.Length / m_nChannels ); } /// /// Encodes a part of the specified interleaved samples. /// /// The samples. /// The samples per channel count. /// /// MemoryStream containing the encoded frames /// public MemoryStream Encode( Array samples, int samplesPerChannelCount ) { MemoryStream stream = new MemoryStream(); this.Encode( samples, samplesPerChannelCount, stream ); return stream; } /// /// Encodes the specified interleaved samples. /// /// The samples. /// The frames. public void Encode( Array samples, Stream frames ) { this.CheckSamplesLength( samples ); this.Encode( samples, samples.Length / m_nChannels, frames ); } /// /// Encodes a part of the specified interleaved samples. /// /// The samples. /// The samples per channel count. /// The frames. public abstract void Encode( Array samples, int samplesPerChannelCount, Stream frames ); /// /// Encodes the specified interleaved samples. /// /// The samples. /// /// MemoryStream containing the encoded frames /// public MemoryStream Encode( Stream samples ) { MemoryStream stream = new MemoryStream(); this.Encode( samples, stream ); return stream; } /// /// Encodes the specified interleaved samples stream. /// /// The samples. /// The frames. public abstract void Encode( Stream samples, Stream frames ); /// /// Encodes the specified interleaved samples and flushes the encoder. This instance needs to be disposed afterwards. /// /// The samples. /// /// MemoryStream containing the encoded frames /// public MemoryStream EncodeAndFlush( Stream samples ) { MemoryStream stream = new MemoryStream(); this.EncodeAndFlush( samples, stream ); return stream; } /// /// Encodes the specified interleaved samples stream and flushes the encoder. This instance needs to be disposed afterwards. /// /// The samples. /// The frames. public void EncodeAndFlush( Stream samples, Stream frames ) { this.Encode( samples, frames ); if ( !this.EncodingDone ) this.Flush( frames ); } #endregion /// /// Flushes the encoder und returns the remaining frames. This instance needs to be disposed afterwards. /// /// MemoryStream containing the encoded frames public MemoryStream Flush() { MemoryStream stream = new MemoryStream(); this.Flush( stream ); return stream; } /// /// Flushes the encoder und returns the remaining frames. This instance needs to be disposed afterwards. /// /// The frames. public abstract void Flush( Stream frames ); /// /// Aborts the encoding. This instance needs to be disposed afterwards. /// public abstract void Abort(); /// /// Initializes a new instance of the class. /// /// The channels. protected FrameEncoder( int channels ) { m_nChannels = channels; } /// /// Releases unmanaged resources and performs other cleanup operations before the /// is reclaimed by garbage collection. /// ~FrameEncoder() { this.Dispose( false ); } } #endregion #region Strongly typed FrameEncoder class /// /// The Aften AC3 Encoder /// /// The type of the sample. public abstract class FrameEncoder : FrameEncoder where TSample : struct { private readonly byte[] m_FrameBuffer = new byte[A52Sizes.MaximumCodedFrameSize]; private readonly byte[] m_StreamBuffer; private readonly TSample[] m_Samples; private readonly TSample[] m_StreamSamples; private readonly int m_nTotalSamplesPerFrame; private readonly int m_nTSampleSize = Marshal.SizeOf( typeof( TSample ) ); private readonly RemappingDelegate m_Remap; private readonly EncodeFrameDelegate m_EncodeFrame; private readonly ToTSampleDelegate m_ToTSample; private EncodingContext m_Context; private int m_nRemainingSamplesCount; private int m_nFrameNumber; private bool m_bFedSamples; private bool m_bGotFrames; private int m_bAbort; internal delegate TSample ToTSampleDelegate( byte[] buffer, int startIndex ); internal delegate int EncodeFrameDelegate( ref EncodingContext context, byte[] frameBuffer, TSample[] samples, int count ); /// /// Delegate for a remapping function /// public delegate void RemappingDelegate( TSample[] samples, int channels, AudioCodingMode audioCodingMode ); /// /// Checks the state of the encoding. /// private void CheckEncodingState() { if ( this.EncodingDone ) throw new InvalidOperationException( "Encoding was already completed. Dispose this object." ); } /// /// Closes the encoder. /// protected override void DoCloseEncoder() { // Context is value type, so I don't want to copy it to the base aften_encode_close( ref m_Context ); } #region Encoding /// /// Encodes the frame. /// /// The samples per channel count. /// private int EncodeFrame( int samplesPerChannelCount ) { if ( samplesPerChannelCount > 0 ) { m_bFedSamples = true; if ( (m_Remap != null) ) m_Remap( m_Samples, m_Context.Channels, m_Context.AudioCodingMode ); } int nSize = m_EncodeFrame( ref m_Context, m_FrameBuffer, m_Samples, samplesPerChannelCount ); if ( nSize > 0 ) { m_bGotFrames = true; this.OnFrameEncoded( this, new FrameEventArgs( ++m_nFrameNumber, nSize, m_Context.Status ) ); } else if ( nSize < 0 ) throw new InvalidOperationException( "Encoding error" ); return nSize; } /// /// Encodes a part of the specified interleaved samples. /// /// The samples. /// The samples per channel count. /// The frames. public override void Encode( Array samples, int samplesPerChannelCount, Stream frames ) { TSample[] typedSamples = (TSample[]) samples; this.Encode( typedSamples, samplesPerChannelCount, frames ); } /// /// Encodes the specified interleaved samples. /// /// The samples. /// MemoryStream containing the encoded frames public MemoryStream Encode( TSample[] samples ) { this.CheckSamplesLength( samples ); return this.Encode( samples, samples.Length / m_Context.Channels ); } /// /// Encodes a part of the specified interleaved samples. /// /// The samples. /// The samples per channel count. /// /// MemoryStream containing the encoded frames /// public MemoryStream Encode( TSample[] samples, int samplesPerChannelCount ) { MemoryStream stream = new MemoryStream(); this.Encode( samples, samplesPerChannelCount, stream ); return stream; } /// /// Encodes the specified interleaved samples. /// /// The samples. /// The frames. public void Encode( TSample[] samples, Stream frames ) { this.CheckSamplesLength( samples ); this.Encode( samples, samples.Length / m_Context.Channels, frames ); } /// /// Encodes a part of the specified interleaved samples. /// /// The samples. /// The samples per channel count. /// The frames. public void Encode( TSample[] samples, int samplesPerChannelCount, Stream frames ) { this.CheckEncodingState(); int nSamplesCount = samplesPerChannelCount * m_Context.Channels; if ( nSamplesCount > samples.Length ) throw new InvalidOperationException( "samples contains less data then specified." ); int nOffset = m_nRemainingSamplesCount; int nSamplesNeeded = m_nTotalSamplesPerFrame - nOffset; int nSamplesDone = 0; while ( nSamplesCount - nSamplesDone + nOffset >= m_nTotalSamplesPerFrame ) { if ( Interlocked.Exchange( ref m_bAbort, 0 ) != 0 ) { this.EncodingDone = true; return; } Buffer.BlockCopy( samples, nSamplesDone * m_nTSampleSize, m_Samples, nOffset * m_nTSampleSize, nSamplesNeeded * m_nTSampleSize ); int nSize = this.EncodeFrame( A52Sizes.SamplesPerFrame ); frames.Write( m_FrameBuffer, 0, nSize ); nSamplesDone += m_nTotalSamplesPerFrame - nOffset; nOffset = 0; nSamplesNeeded = m_nTotalSamplesPerFrame; } m_nRemainingSamplesCount = nSamplesCount - nSamplesDone; if ( m_nRemainingSamplesCount > 0 ) Buffer.BlockCopy( samples, nSamplesDone * m_nTSampleSize, m_Samples, 0, m_nRemainingSamplesCount * m_nTSampleSize ); } /// /// Encodes the specified interleaved samples stream and flushes the encoder. /// /// The samples. /// The frames. public override void Encode( Stream samples, Stream frames ) { this.CheckEncodingState(); if ( !samples.CanRead ) throw new InvalidOperationException( "Samples stream must be readable." ); int nOffset = 0; int nCurrentRead; while ( (nCurrentRead = samples.Read( m_StreamBuffer, 0, m_nTSampleSize )) == m_nTSampleSize ) { m_StreamSamples[nOffset] = m_ToTSample( m_StreamBuffer, 0 ); ++nOffset; if ( nOffset == m_nTotalSamplesPerFrame ) { this.Encode( m_StreamSamples, frames ); nOffset = 0; if ( this.EncodingDone ) return; } } if ( (nCurrentRead != 0) || (nOffset % m_Context.Channels != 0) ) throw new InvalidOperationException( _EqualAmountOfSamples ); if ( nOffset > 0 ) this.Encode( m_StreamSamples, nOffset / m_Context.Channels, frames ); } #endregion /// /// Flushes the encoder und returns the remaining frames. This instance needs to be disposed afterwards. /// /// The frames. public override void Flush( Stream frames ) { this.CheckEncodingState(); int nSize; int nSamplesPerChannelCount = m_nRemainingSamplesCount / m_Context.Channels; do { nSize = this.EncodeFrame( nSamplesPerChannelCount ); frames.Write( m_FrameBuffer, 0, nSize ); nSamplesPerChannelCount = 0; } while ( nSize > 0 || (m_bFedSamples && !m_bGotFrames) ); this.EncodingDone = true; } /// /// Aborts the encoding. This instance needs to be disposed afterwards. /// public override void Abort() { Interlocked.Exchange( ref m_bAbort, 1 ); } /// /// Initializes a new instance of the class. /// /// The context. /// The remapping function. /// The encode frame function. /// The ToTSample function. /// The sample format. internal FrameEncoder( ref EncodingContext context, RemappingDelegate remap, EncodeFrameDelegate encodeFrame, ToTSampleDelegate toTSample, A52SampleFormat sampleFormat ) : this( ref context, encodeFrame, toTSample, sampleFormat ) { m_Remap = remap; } /// /// Initializes a new instance of the class. /// /// The context. /// The encode frame function. /// The ToTSample function. /// The sample format. internal FrameEncoder( ref EncodingContext context, EncodeFrameDelegate encodeFrame, ToTSampleDelegate toTSample, A52SampleFormat sampleFormat ) : base( context.Channels ) { if ( aften_encode_init( ref context ) != 0 ) throw new InvalidOperationException( "Initialization failed" ); context.SampleFormat = sampleFormat; m_Context = context; m_EncodeFrame = encodeFrame; m_ToTSample = toTSample; m_nTotalSamplesPerFrame = A52Sizes.SamplesPerFrame * m_Context.Channels; m_Samples = new TSample[m_nTotalSamplesPerFrame]; m_StreamSamples = new TSample[m_nTotalSamplesPerFrame]; m_StreamBuffer = new byte[m_nTSampleSize]; } } #endregion #region Specific FrameEncoder classes /// /// The Aften AC3 Encoder for double precision floating point samples, normalized to [-1, 1] /// public class FrameEncoderDouble : FrameEncoder { [DllImport( "aften.dll" )] private static extern int aften_encode_frame( ref EncodingContext context, byte[] frameBuffer, double[] samples, int count ); /// /// Initializes a new instance of the class. /// /// The context. /// The remapping function. public FrameEncoderDouble( ref EncodingContext context, RemappingDelegate remap ) : base( ref context, remap, aften_encode_frame, BitConverter.ToDouble, A52SampleFormat.Double ) { } /// /// Initializes a new instance of the class. /// /// The context. public FrameEncoderDouble( ref EncodingContext context ) : base( ref context, aften_encode_frame, BitConverter.ToDouble, A52SampleFormat.Double ) { } } /// /// The Aften AC3 Encoder for single precision floating point samples, normalized to [-1, 1] /// public class FrameEncoderFloat : FrameEncoder { [DllImport( "aften.dll" )] private static extern int aften_encode_frame( ref EncodingContext context, byte[] frameBuffer, float[] samples, int count ); /// /// Initializes a new instance of the class. /// /// The context. /// The remapping function. public FrameEncoderFloat( ref EncodingContext context, RemappingDelegate remap ) : base( ref context, remap, aften_encode_frame, BitConverter.ToSingle, A52SampleFormat.Float ) { } /// /// Initializes a new instance of the class. /// /// The context. public FrameEncoderFloat( ref EncodingContext context ) : base( ref context, aften_encode_frame, BitConverter.ToSingle, A52SampleFormat.Float ) { } } /// /// The Aften AC3 Encoder for 8bit unsigned integer samples /// public class FrameEncoderUInt8 : FrameEncoder { [DllImport( "aften.dll" )] private static extern int aften_encode_frame( ref EncodingContext context, byte[] frameBuffer, byte[] samples, int count ); /// /// Returns the byte at the startIndex /// /// The value. /// The start index. /// private static byte ToUInt8( byte[] value, int startIndex ) { return value[startIndex]; } /// /// Initializes a new instance of the class. /// /// The context. /// The remapping function. public FrameEncoderUInt8( ref EncodingContext context, RemappingDelegate remap ) : base( ref context, remap, aften_encode_frame, ToUInt8, A52SampleFormat.UInt8 ) { } /// /// Initializes a new instance of the class. /// /// The context. public FrameEncoderUInt8( ref EncodingContext context ) : base( ref context, aften_encode_frame, ToUInt8, A52SampleFormat.UInt8 ) { } } /// /// The Aften AC3 Encoder for 8bit signed integer samples /// public class FrameEncoderInt8 : FrameEncoder { [DllImport( "aften.dll" )] private static extern int aften_encode_frame( ref EncodingContext context, byte[] frameBuffer, sbyte[] samples, int count ); /// /// Returns the signed byte at the startIndex /// /// The value. /// The start index. /// private static sbyte ToInt8( byte[] value, int startIndex ) { return (sbyte) value[startIndex]; } /// /// Initializes a new instance of the class. /// /// The context. /// The remapping function. public FrameEncoderInt8( ref EncodingContext context, RemappingDelegate remap ) : base( ref context, remap, aften_encode_frame, ToInt8, A52SampleFormat.Int8 ) { } /// /// Initializes a new instance of the class. /// /// The context. public FrameEncoderInt8( ref EncodingContext context ) : base( ref context, aften_encode_frame, ToInt8, A52SampleFormat.Int8 ) { } } /// /// The Aften AC3 Encoder for 16bit signed integer samples /// public class FrameEncoderInt16 : FrameEncoder { [DllImport( "aften.dll" )] private static extern int aften_encode_frame( ref EncodingContext context, byte[] frameBuffer, short[] samples, int count ); /// /// Initializes a new instance of the class. /// /// The context. /// The remapping function. public FrameEncoderInt16( ref EncodingContext context, RemappingDelegate remap ) : base( ref context, remap, aften_encode_frame, BitConverter.ToInt16, A52SampleFormat.Int16 ) { } /// /// Initializes a new instance of the class. /// /// The context. public FrameEncoderInt16( ref EncodingContext context ) : base( ref context, aften_encode_frame, BitConverter.ToInt16, A52SampleFormat.Int16 ) { } } /// /// The Aften AC3 Encoder for 32bit signed integer samples /// public class FrameEncoderInt32 : FrameEncoder { [DllImport( "aften.dll" )] private static extern int aften_encode_frame( ref EncodingContext context, byte[] frameBuffer, int[] samples, int count ); /// /// Initializes a new instance of the class. /// /// The context. /// The remapping function. public FrameEncoderInt32( ref EncodingContext context, RemappingDelegate remap ) : base( ref context, remap, aften_encode_frame, BitConverter.ToInt32, A52SampleFormat.Int32 ) { } /// /// Initializes a new instance of the class. /// /// The context. public FrameEncoderInt32( ref EncodingContext context ) : base( ref context, aften_encode_frame, BitConverter.ToInt32, A52SampleFormat.Int32 ) { } } #endregion } aften/bindings/cs/FrameEventArgs.cs000066400000000000000000000051251132016273200175550ustar00rootroot00000000000000/******************************************************************************** * Copyright (C) 2007 by Prakash Punnoor * * prakash@punnoor.de * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * ********************************************************************************/ using System; namespace Aften { /// /// EventArgs for frame related events /// public class FrameEventArgs : EventArgs { private readonly int m_nFrameNumber; private readonly int m_nSize; private readonly Status m_Status; /// /// Gets the status. /// /// The status. public Status Status { get { return m_Status; } } /// /// Gets the size of the encoded frame. /// /// The size. public int Size { get { return m_nSize; } } /// /// Gets the frame number. /// /// The frame number. public int FrameNumber { get { return m_nFrameNumber; } } /// /// Initializes a new instance of the class. /// /// The frame number. /// The size of the encoded frame. /// The status. public FrameEventArgs( int frameNumber, int size, Status status ) { m_nFrameNumber = frameNumber; m_nSize = size; m_Status = status; } } } aften/bindings/cs/Utility.cs000066400000000000000000000246331132016273200163540ustar00rootroot00000000000000/******************************************************************************** * Copyright (C) 2007 by Prakash Punnoor * * prakash@punnoor.de * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * ********************************************************************************/ using System; using System.Runtime.InteropServices; namespace Aften { /// /// Utility functions /// public static class Utility { [DllImport( "aften.dll" )] private static extern IntPtr aften_get_version(); // returns string not on heap! [DllImport( "aften.dll" )] private static extern int aften_wav_channels_to_acmod( int ch, uint chmask, out AudioCodingMode acmod, out bool lfe ); [DllImport( "aften.dll" )] private static extern int aften_remap_wav_to_a52( double[] samples, int n, int ch, A52SampleFormat fmt, AudioCodingMode acmod ); [DllImport( "aften.dll" )] private static extern int aften_remap_wav_to_a52( float[] samples, int n, int ch, A52SampleFormat fmt, AudioCodingMode acmod ); [DllImport( "aften.dll" )] private static extern int aften_remap_wav_to_a52( byte[] samples, int n, int ch, A52SampleFormat fmt, AudioCodingMode acmod ); [DllImport( "aften.dll" )] private static extern int aften_remap_wav_to_a52( sbyte[] samples, int n, int ch, A52SampleFormat fmt, AudioCodingMode acmod ); [DllImport( "aften.dll" )] private static extern int aften_remap_wav_to_a52( short[] samples, int n, int ch, A52SampleFormat fmt, AudioCodingMode acmod ); [DllImport( "aften.dll" )] private static extern int aften_remap_wav_to_a52( int[] samples, int n, int ch, A52SampleFormat fmt, AudioCodingMode acmod ); [DllImport( "aften.dll" )] private static extern int aften_remap_mpeg_to_a52( double[] samples, int n, int ch, A52SampleFormat fmt, AudioCodingMode acmod ); [DllImport( "aften.dll" )] private static extern int aften_remap_mpeg_to_a52( float[] samples, int n, int ch, A52SampleFormat fmt, AudioCodingMode acmod ); [DllImport( "aften.dll" )] private static extern int aften_remap_mpeg_to_a52( byte[] samples, int n, int ch, A52SampleFormat fmt, AudioCodingMode acmod ); [DllImport( "aften.dll" )] private static extern int aften_remap_mpeg_to_a52( sbyte[] samples, int n, int ch, A52SampleFormat fmt, AudioCodingMode acmod ); [DllImport( "aften.dll" )] private static extern int aften_remap_mpeg_to_a52( short[] samples, int n, int ch, A52SampleFormat fmt, AudioCodingMode acmod ); [DllImport( "aften.dll" )] private static extern int aften_remap_mpeg_to_a52( int[] samples, int n, int ch, A52SampleFormat fmt, AudioCodingMode acmod ); [DllImport( "aften.dll" )] private static extern FloatType aften_get_float_type(); /// /// Gets the version. /// /// public static string GetVersion() { return Marshal.PtrToStringAuto( aften_get_version() ); } /// /// Gets the audio coding mode from the specified channels and mask /// /// The channels. /// The channel mask. /// if set to true has lfe. /// public static AudioCodingMode GetAudioCodingMode( int channels, uint channelMask, out bool hasLfe ) { AudioCodingMode audioCodingMode; if ( aften_wav_channels_to_acmod( channels, channelMask, out audioCodingMode, out hasLfe ) != 0 ) throw new InvalidOperationException( "channels or channelMask are not valid" ); return audioCodingMode; } /// /// Remaps the standard wave to a52 order. /// /// The samples. /// The channels. /// The audio coding mode. public static void RemapWaveToA52( double[] samples, int channels, AudioCodingMode audioCodingMode ) { aften_remap_wav_to_a52( samples, samples.Length / channels, channels, A52SampleFormat.Double, audioCodingMode ); } /// /// Remaps the standard wave to a52 order. /// /// The samples. /// The channels. /// The audio coding mode. public static void RemapWaveToA52( float[] samples, int channels, AudioCodingMode audioCodingMode ) { aften_remap_wav_to_a52( samples, samples.Length / channels, channels, A52SampleFormat.Float, audioCodingMode ); } /// /// Remaps the standard wave to a52 order. /// /// The samples. /// The channels. /// The audio coding mode. public static void RemapWaveToA52( byte[] samples, int channels, AudioCodingMode audioCodingMode ) { aften_remap_wav_to_a52( samples, samples.Length / channels, channels, A52SampleFormat.UInt8, audioCodingMode ); } /// /// Remaps the standard wave to a52 order. /// /// The samples. /// The channels. /// The audio coding mode. public static void RemapWaveToA52( sbyte[] samples, int channels, AudioCodingMode audioCodingMode ) { aften_remap_wav_to_a52( samples, samples.Length / channels, channels, A52SampleFormat.Int8, audioCodingMode ); } /// /// Remaps the standard wave to a52 order. /// /// The samples. /// The channels. /// The audio coding mode. public static void RemapWaveToA52( short[] samples, int channels, AudioCodingMode audioCodingMode ) { aften_remap_wav_to_a52( samples, samples.Length / channels, channels, A52SampleFormat.Int16, audioCodingMode ); } /// /// Remaps the standard wave to a52 order. /// /// The samples. /// The channels. /// The audio coding mode. public static void RemapWaveToA52( int[] samples, int channels, AudioCodingMode audioCodingMode ) { aften_remap_wav_to_a52( samples, samples.Length / channels, channels, A52SampleFormat.Int32, audioCodingMode ); } /// /// Remaps the MPEG to a52 order. /// /// The samples. /// The channels. /// The audio coding mode. public static void RemapMpegToA52( double[] samples, int channels, AudioCodingMode audioCodingMode ) { aften_remap_mpeg_to_a52( samples, samples.Length / channels, channels, A52SampleFormat.Double, audioCodingMode ); } /// /// Remaps the MPEG to a52 order. /// /// The samples. /// The channels. /// The audio coding mode. public static void RemapMpegToA52( float[] samples, int channels, AudioCodingMode audioCodingMode ) { aften_remap_mpeg_to_a52( samples, samples.Length / channels, channels, A52SampleFormat.Float, audioCodingMode ); } /// /// Remaps the MPEG to a52 order. /// /// The samples. /// The channels. /// The audio coding mode. public static void RemapMpegToA52( byte[] samples, int channels, AudioCodingMode audioCodingMode ) { aften_remap_mpeg_to_a52( samples, samples.Length / channels, channels, A52SampleFormat.UInt8, audioCodingMode ); } /// /// Remaps the MPEG to a52 order. /// /// The samples. /// The channels. /// The audio coding mode. public static void RemapMpegToA52( sbyte[] samples, int channels, AudioCodingMode audioCodingMode ) { aften_remap_mpeg_to_a52( samples, samples.Length / channels, channels, A52SampleFormat.Int8, audioCodingMode ); } /// /// Remaps the MPEG to a52 order. /// /// The samples. /// The channels. /// The audio coding mode. public static void RemapMpegToA52( short[] samples, int channels, AudioCodingMode audioCodingMode ) { aften_remap_mpeg_to_a52( samples, samples.Length / channels, channels, A52SampleFormat.Int16, audioCodingMode ); } /// /// Remaps the MPEG to a52 order. /// /// The samples. /// The channels. /// The audio coding mode. public static void RemapMpegToA52( int[] samples, int channels, AudioCodingMode audioCodingMode ) { aften_remap_mpeg_to_a52( samples, samples.Length / channels, channels, A52SampleFormat.Int32, audioCodingMode ); } /// /// Gets the float precision of the compiled Aften library /// /// public static FloatType GetFloatType() { return aften_get_float_type(); } } } aften/bswap.h000066400000000000000000000036721132016273200134450ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * Copyright (c) 2006 Justin Ruggles * * Based on "The simplest AC3 encoder" from FFmpeg * Copyright (c) 2000 Fabrice Bellard. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file bswap.h * Byte swap */ #ifndef BSWAP_H #define BSWAP_H #include "common.h" #ifdef HAVE_BYTESWAP_H #include #else static inline uint16_t bswap_16(uint16_t x) { return (x>>8) | (x<<8); } static inline uint32_t bswap_32(uint32_t x) { x= ((x<<8)&0xFF00FF00) | ((x>>8)&0x00FF00FF); return (x>>16) | (x<<16); } static inline uint64_t bswap_64(uint64_t x) { union { uint64_t ll; uint32_t l[2]; } w, r; w.ll = x; r.l[0] = bswap_32(w.l[1]); r.l[1] = bswap_32(w.l[0]); return r.ll; } #endif /* !HAVE_BYTESWAP_H */ // be2me ... BigEndian to MachineEndian // le2me ... LittleEndian to MachineEndian #ifdef WORDS_BIGENDIAN #define be2me_16(x) (x) #define be2me_32(x) (x) #define be2me_64(x) (x) #define le2me_16(x) bswap_16(x) #define le2me_32(x) bswap_32(x) #define le2me_64(x) bswap_64(x) #else #define be2me_16(x) bswap_16(x) #define be2me_32(x) bswap_32(x) #define be2me_64(x) bswap_64(x) #define le2me_16(x) (x) #define le2me_32(x) (x) #define le2me_64(x) (x) #endif #endif /* BSWAP_H */ aften/common.h000066400000000000000000000110271132016273200136120ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * Copyright (c) 2006 Justin Ruggles * * Based on "The simplest AC3 encoder" from FFmpeg * Copyright (c) 2000 Fabrice Bellard. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file common.h * Common header file */ #ifndef COMMON_H #define COMMON_H #ifdef HAVE_CONFIG_H #include "config.h" #endif #ifdef HAVE_POSIX_MEMALIGN #define _XOPEN_SOURCE 600 #endif #include #include #include #include #include #ifdef HAVE_INTTYPES_H #include #else #if defined(_WIN32) && defined(_MSC_VER) // integer types typedef __int8 int8_t; typedef unsigned __int8 uint8_t; typedef __int16 int16_t; typedef unsigned __int16 uint16_t; typedef __int32 int32_t; typedef unsigned __int32 uint32_t; typedef __int64 int64_t; typedef unsigned __int64 uint64_t; // limits #define INT8_MIN _I8_MIN #define INT8_MAX _I8_MAX #define UINT8_MAX _UI8_MAX #define INT16_MIN _I16_MIN #define INT16_MAX _I16_MAX #define UINT16_MAX _UI16_MAX #define INT32_MIN _I32_MIN #define INT32_MAX _I32_MAX #define UINT32_MAX _UI32_MAX #define INT64_MIN _I64_MIN #define INT64_MAX _I64_MAX #define UINT64_MAX _UI64_MAX // fprintf macros #define PRId8 "d" #define PRIi8 "i" #define PRIo8 "o" #define PRIu8 "u" #define PRIx8 "x" #define PRIX8 "X" #define PRId16 "hd" #define PRIi16 "hi" #define PRIo16 "ho" #define PRIu16 "hu" #define PRIx16 "hx" #define PRIX16 "hX" #define PRId32 "I32d" #define PRIi32 "I32i" #define PRIo32 "I32o" #define PRIu32 "I32u" #define PRIx32 "I32x" #define PRIX32 "I32X" #define PRId64 "I64d" #define PRIi64 "I64i" #define PRIo64 "I64o" #define PRIu64 "I64u" #define PRIx64 "I64x" #define PRIX64 "I64X" #endif #endif /* EMULATE_INTTYPES */ #if __GNUC__ && !__INTEL_COMPILER #define ALIGN16(x) x __attribute__((aligned(16))) #else #if defined(_MSC_VER) || defined(__INTEL_COMPILER) #define ALIGN16(x) __declspec(align(16)) x #else #define ALIGN16(x) x #endif #endif #ifdef _WIN32 #define CDECL __cdecl #ifdef _MSC_VER #define inline __inline #endif /* _MSC_VER */ #else #define CDECL #endif #if __GNUC__ #define UNUSED(x) x __attribute__((unused)) #else #define UNUSED(x) x #endif #ifdef CONFIG_DOUBLE typedef double FLOAT; #define FCONST(X) (X) #define AFT_COS cos #define AFT_SIN sin #define AFT_TAN tan #define AFT_LOG10 log10 #define AFT_EXP exp #define AFT_FABS fabs #define AFT_SQRT sqrt #define AFT_EXP exp #else typedef float FLOAT; #define FCONST(X) (X##f) #define AFT_COS cosf #define AFT_SIN sinf #define AFT_TAN tanf #define AFT_LOG10 log10f #define AFT_FABS fabsf #define AFT_SQRT sqrtf #define AFT_EXP expf #endif #define AFT_PI FCONST(3.14159265358979323846) #define AFT_SQRT2 FCONST(1.41421356237309504880) #define AFT_LN10 FCONST(2.30258509299404568402) #define AFT_EXP10(x) AFT_EXP((x) * AFT_LN10) #define ABS(a) ((a) >= 0 ? (a) : (-(a))) #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define MIN(a,b) ((a) > (b) ? (b) : (a)) #define CLIP(x,min,max) MAX(MIN((x), (max)), (min)) #include "bswap.h" #if 0 /* TIMER USED FOR TESTING */ static inline uint64_t read_time(void) { uint32_t a, d; __asm__ volatile("rdtsc" : "=a" (a), "=d" (d)); return ((uint64_t)d << 32) + a; } #define START_TIMER \ uint64_t tend;\ uint64_t tstart = read_time();\ #define STOP_TIMER(id) \ tend= read_time();\ {\ static uint64_t tsum=0;\ static int tcount=0;\ static int tskip_count=0;\ if(tcount<2 || tend - tstart < MAX(8*tsum/tcount, 2000)){\ tsum+= tend - tstart;\ tcount++;\ }else\ tskip_count++;\ if(((tcount+tskip_count)&(tcount+tskip_count-1))==0){\ fprintf(stderr, "%"PRIu64" dezicycles in %s, %d runs, %d skips\n",\ tsum*10/tcount, id, tcount, tskip_count);\ }\ } #endif #endif /* COMMON_H */ aften/libaften/000077500000000000000000000000001132016273200137345ustar00rootroot00000000000000aften/libaften/a52.c000066400000000000000000000161051132016273200144720ustar00rootroot00000000000000/** * Aften: A/52 audio encoder - Common code between encoder and decoder * Copyright (c) 2008 Prakash Punnoor * * Based on "The simplest AC3 encoder" from FFmpeg * Copyright (c) 2000 Fabrice Bellard. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file a52.c * Common code between A/52 encoder and decoder. */ #include "a52.h" static uint8_t band_start_tab[51]; static uint8_t bin_to_band_tab[253]; static inline int calc_lowcomp1(int a, int b0, int b1, int c) { if ((b0 + 256) == b1) a = c; else if (b0 > b1) a = MAX(a - 64, 0); return a; } static inline int calc_lowcomp(int a, int b0, int b1, int bin) { if (bin < 7) return calc_lowcomp1(a, b0, b1, 384); else if (bin < 20) return calc_lowcomp1(a, b0, b1, 320); else return MAX(a - 128, 0); } void a52_bit_alloc_calc_psd(uint8_t *exp, int start, int end, int16_t *psd, int16_t *band_psd) { int bin, band; /* exponent mapping to PSD */ for (bin = start; bin < end; bin++) psd[bin] = 3072 - (exp[bin] << 7); /* PSD integration */ bin = start; band = bin_to_band_tab[start]; do { int v = psd[bin++]; int band_end = MIN(band_start_tab[band+1], end); for (; bin < band_end; bin++) { /* logadd */ int adr = MIN(ABS(v - psd[bin]) >> 1, 255); v = MAX(v, psd[bin]) + a52_log_add_tab[adr]; } band_psd[band++] = v; } while (end > band_start_tab[band]); } void a52_bit_alloc_calc_mask(A52BitAllocParams *s, int16_t *band_psd, int start, int end, int fast_gain, int dba_mode, int dba_nsegs, uint8_t *dba_offsets, uint8_t *dba_lengths, uint8_t *dba_values, int16_t *mask) { int16_t excite[50]; /* excitation */ int band; int band_start, band_end, begin, end1; int lowcomp, fastleak, slowleak; /* excitation function */ band_start = bin_to_band_tab[start]; band_end = bin_to_band_tab[end-1] + 1; if (band_start == 0) { lowcomp = 0; lowcomp = calc_lowcomp1(lowcomp, band_psd[0], band_psd[1], 384); excite[0] = band_psd[0] - fast_gain - lowcomp; lowcomp = calc_lowcomp1(lowcomp, band_psd[1], band_psd[2], 384); excite[1] = band_psd[1] - fast_gain - lowcomp; begin = 7; for (band = 2; band < 7; band++) { if (!(band_end == 7 && band == 6)) lowcomp = calc_lowcomp1(lowcomp, band_psd[band], band_psd[band+1], 384); fastleak = band_psd[band] - fast_gain; slowleak = band_psd[band] - s->sgain; excite[band] = fastleak - lowcomp; if (!(band_end == 7 && band == 6)) { if (band_psd[band] <= band_psd[band+1]) { begin = band + 1; break; } } } end1 = MIN(band_end, 22); for (band = begin; band < end1; band++) { if (!(band_end == 7 && band == 6)) lowcomp = calc_lowcomp(lowcomp, band_psd[band], band_psd[band+1], band); fastleak = MAX(fastleak - s->fdecay, band_psd[band] - fast_gain); slowleak = MAX(slowleak - s->sdecay, band_psd[band] - s->sgain); excite[band] = MAX(fastleak - lowcomp, slowleak); } begin = 22; } else { /* coupling channel */ begin = band_start; fastleak = (s->cplfleak << 8) + 768; slowleak = (s->cplsleak << 8) + 768; } for (band = begin; band < band_end; band++) { fastleak = MAX(fastleak - s->fdecay, band_psd[band] - fast_gain); slowleak = MAX(slowleak - s->sdecay, band_psd[band] - s->sgain); excite[band] = MAX(fastleak, slowleak); } /* compute masking curve */ for (band = band_start; band < band_end; band++) { int tmp = s->dbknee - band_psd[band]; if (tmp > 0) excite[band] += tmp >> 2; mask[band] = MAX(a52_hearing_threshold_tab[band >> s->halfratecod][s->fscod], excite[band]); } /* delta bit allocation */ if (dba_mode == DBA_REUSE || dba_mode == DBA_NEW) { int i, band, seg, delta; dba_nsegs = MIN(dba_nsegs, 8); band = 0; for (seg = 0; seg < dba_nsegs; seg++) { band += dba_offsets[seg]; if (dba_values[seg] >= 4) delta = (dba_values[seg] - 3) << 7; else delta = (dba_values[seg] - 4) << 7; for (i = 0; i < dba_lengths[seg] && band < 50; i++) mask[band++] += delta; } } } /** * A52 bit allocation * Generate bit allocation pointers for each mantissa, which determines the * number of bits allocated for each mantissa. The fine-grain power-spectral * densities and the masking curve have been pre-generated in the preparation * step. They are used along with the given snroffset and floor values to * calculate each bap value. */ void a52_bit_alloc_calc_bap(int16_t *mask, int16_t *psd, int start, int end, int snr_offset, int floor, uint8_t *bap) { int bin, band; // special case, if snr offset is -960, set all bap's to zero if (snr_offset == -960) { memset(bap, 0, 256); return; } bin = start; band = bin_to_band_tab[start]; do { int m = (MAX(mask[band] - snr_offset - floor, 0) & 0x1FE0) + floor; int band_end = MIN(band_start_tab[band+1], end); if ((band_end - bin) & 1) { int address = CLIP((psd[bin] - m) >> 5, 0, 63); bap[bin++] = a52_bap_tab[address]; } while (bin < band_end) { int address1 = CLIP((psd[bin ] - m) >> 5, 0, 63); int address2 = CLIP((psd[bin+1] - m) >> 5, 0, 63); bap[bin ] = a52_bap_tab[address1]; bap[bin+1] = a52_bap_tab[address2]; bin += 2; } } while (end > band_start_tab[band++]); } /** * Initializes some tables. */ void a52_common_init(void) { /* populate band_start_tab[] and bin_to_band_tab[] from a52_critical_band_size_tab[] */ int bin = 0, band; for (band = 0; band < 50; band++) { int band_end = bin + a52_critical_band_size_tab[band]; band_start_tab[band] = bin; while (bin < band_end) bin_to_band_tab[bin++] = band; } band_start_tab[50] = bin; } aften/libaften/a52.h000066400000000000000000000142561132016273200145040ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * Copyright (c) 2006 Justin Ruggles * * Based on "The simplest AC3 encoder" from FFmpeg * Copyright (c) 2000 Fabrice Bellard. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file a52.h * A/52 common header */ #ifndef A52_H #define A52_H #include "common.h" #include "a52tab.h" #include "aften-types.h" #define AFTEN_VERSION "git" #define A52_MAX_CHANNELS 6 #define A52_NUM_BLOCKS 6 /* exponent encoding strategy */ #define EXP_REUSE 0 #define EXP_NEW 1 #define EXP_D15 1 #define EXP_D25 2 #define EXP_D45 3 #define QUALITY(csnr, fsnr) (((csnr) << 4) | (fsnr)) extern const uint8_t log2tab[256]; static inline int log2i(uint32_t v) { int n = 0; if (v & 0xffff0000) { v >>= 16; n += 16; } if (v & 0xff00) { v >>= 8; n += 8; } n += log2tab[v]; return n; } /** Delta bit allocation strategy */ typedef enum { DBA_REUSE = 0, DBA_NEW, DBA_NONE, DBA_RESERVED } AC3DeltaStrategy; typedef struct A52Block { FLOAT *input_samples[A52_MAX_CHANNELS]; /* 512 per ch */ FLOAT *mdct_coef[A52_MAX_CHANNELS]; /* 256 per ch */ FLOAT transient_samples[A52_MAX_CHANNELS][512]; int block_num; int blksw[A52_MAX_CHANNELS]; int dithflag[A52_MAX_CHANNELS]; int dynrng; uint8_t exp[A52_MAX_CHANNELS][256]; int16_t psd[A52_MAX_CHANNELS][256]; int16_t mask[A52_MAX_CHANNELS][50]; uint8_t exp_strategy[A52_MAX_CHANNELS]; uint8_t nexpgrps[A52_MAX_CHANNELS]; uint8_t grp_exp[A52_MAX_CHANNELS][85]; uint8_t bap[A52_MAX_CHANNELS][256]; uint16_t qmant[A52_MAX_CHANNELS][256]; int fgaincod[A52_MAX_CHANNELS]; int write_snr; } A52Block; typedef struct A52BitAllocParams { int fscod; int halfratecod; int fgain[A52_NUM_BLOCKS][A52_MAX_CHANNELS]; int sgain, sdecay, fdecay, dbknee, floor; int cplfleak, cplsleak; } A52BitAllocParams; typedef struct A52Frame { int quality; int bit_rate; int bwcode; FLOAT input_audio[A52_MAX_CHANNELS][A52_SAMPLES_PER_FRAME]; A52Block blocks[A52_NUM_BLOCKS]; int frame_bits; int exp_bits; int mant_bits; unsigned int frame_size_min; // minimum frame size unsigned int frame_size; // current frame size in words unsigned int frmsizecod; // bitrate allocation control int sgaincod, sdecaycod, fdecaycod, dbkneecod, floorcod; A52BitAllocParams bit_alloc; int csnroffst; int fsnroffst; int ncoefs[A52_MAX_CHANNELS]; int expstr_set[A52_MAX_CHANNELS]; uint8_t rematflg[4]; } A52Frame; void a52_common_init(void); /** * Calculates the log power-spectral density of the input signal. * This gives a rough estimate of signal power in the frequency domain by using * the spectral envelope (exponents). The psd is also separately grouped * into critical bands for use in the calculating the masking curve. * 128 units in psd = -6 dB. The dbknee parameter in AC3BitAllocParameters * determines the reference level. * * @param[in] exp frequency coefficient exponents * @param[in] start starting bin location * @param[in] end ending bin location * @param[out] psd signal power for each frequency bin * @param[out] band_psd signal power for each critical band */ void a52_bit_alloc_calc_psd(uint8_t *exp, int start, int end, int16_t *psd, int16_t *band_psd); /** * Calculates the masking curve. * First, the excitation is calculated using parameters in \p s and the signal * power in each critical band. The excitation is compared with a predefined * hearing threshold table to produce the masking curve. If delta bit * allocation information is provided, it is used for adjusting the masking * curve, usually to give a closer match to a better psychoacoustic model. * * @param[in] s adjustable bit allocation parameters * @param[in] band_psd signal power for each critical band * @param[in] start starting bin location * @param[in] end ending bin location * @param[in] fast_gain fast gain (estimated signal-to-mask ratio) * @param[in] dba_mode delta bit allocation mode (none, reuse, or new) * @param[in] dba_nsegs number of delta segments * @param[in] dba_offsets location offsets for each segment * @param[in] dba_lengths length of each segment * @param[in] dba_values delta bit allocation for each segment * @param[out] mask calculated masking curve */ void a52_bit_alloc_calc_mask(A52BitAllocParams *s, int16_t *band_psd, int start, int end, int fast_gain, int dba_mode, int dba_nsegs, uint8_t *dba_offsets, uint8_t *dba_lengths, uint8_t *dba_values, int16_t *mask); /** * Calculates bit allocation pointers. * The SNR is the difference between the masking curve and the signal. AC-3 * uses this value for each frequency bin to allocate bits. The \p snroffset * parameter is a global adjustment to the SNR for all bins. * * @param[in] mask masking curve * @param[in] psd signal power for each frequency bin * @param[in] start starting bin location * @param[in] end ending bin location * @param[in] snr_offset SNR adjustment * @param[in] floor noise floor * @param[out] bap bit allocation pointers */ void a52_bit_alloc_calc_bap(int16_t *mask, int16_t *psd, int start, int end, int snr_offset, int floor, uint8_t *bap); #endif /* A52_H */ aften/libaften/a52dec.h000066400000000000000000000013601132016273200151500ustar00rootroot00000000000000#ifndef A52DEC_H #define A52DEC_H #include "a52.h" typedef struct { uint8_t *input_frame_buffer; int input_frame_buffer_size; int channel_mode; int fbw_channels; int lfe_on; int sample_rate; int bsid; int bsmod; int cmixlev; int surmixlev; int dsurmod; A52BitAllocParams bit_alloc_params; } A52DecodeContext; struct A52ThreadContext; static inline void a52_decode_init(){} static inline void a52_decode_init_thread(UNUSED(struct A52ThreadContext *tctx)){} static inline int a52_decode_frame(UNUSED(struct A52ThreadContext *tctx)){return 0;} static inline void a52_decode_deinit_thread(UNUSED(struct A52ThreadContext *tctx)){} static inline int a52_get_frame_size(UNUSED(A52DecodeContext *s)){return 0;} #endif /* A52DEC_H */ aften/libaften/a52enc.c000066400000000000000000001475271132016273200151750ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * Copyright (c) 2006 Justin Ruggles * 2007 Prakash Punnoor * * Based on "The simplest AC3 encoder" from FFmpeg * Copyright (c) 2000 Fabrice Bellard. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file a52enc.c * A/52 encoder */ #include "a52enc.h" #include "bitalloc.h" #include "crc.h" #include "window.h" #include "dynrng.h" #include "cpu_caps.h" #include "convert.h" /** * LUT for number of exponent groups present. * expsizetab[exponent strategy][number of coefficients] */ int nexpgrptab[3][256] = {{0}}; static const uint8_t rematbndtab[5] = { 13, 25, 37, 61, 252 }; static void copy_samples(A52ThreadContext *tctx); static int convert_samples_from_src(A52ThreadContext *tctx, const void *vsrc, int count); static int begin_encode_frame(A52ThreadContext *tctx); static int begin_transcode_frame(A52ThreadContext *tctx); static int prepare_transcode_common(A52ThreadContext *tctx, const void *input_frame_buffer, int input_frame_buffer_size, int *want_bytes) { int frame_size; if (input_frame_buffer_size < 6) { *want_bytes = 6; return -1; } memcpy(tctx->dctx->input_frame_buffer, input_frame_buffer, 6); frame_size = a52_get_frame_size(tctx->dctx); *want_bytes = -1; if (frame_size > 0) { memcpy( (uint8_t*)tctx->dctx->input_frame_buffer + 6, (uint8_t*)input_frame_buffer + 6, frame_size - 6); *want_bytes = frame_size; tctx->dctx->input_frame_buffer_size = frame_size; } return -(input_frame_buffer_size < frame_size); } #ifndef NO_THREADS static int threaded_worker(void* vtctx); static int prepare_encode(A52ThreadContext *tctx, const void *samples, int count, UNUSED(int *info)) { A52Context *ctx = tctx->ctx; // append extra silent frame if final frame is > 1280 samples, to flush 256 samples in mdct if (ctx->last_samples_count <= (A52_SAMPLES_PER_FRAME - 256) && ctx->last_samples_count != -1) { tctx->state = END; --ctx->ts.threads_running; } else { // convert sample format and de-interleave channels convert_samples_from_src(tctx, samples, count); ctx->last_samples_count = count; } return 0; } static int prepare_transcode(A52ThreadContext *tctx, const void *input_frame_buffer, int input_frame_buffer_size, int *want_bytes) { if (!input_frame_buffer_size) { tctx->state = END; --tctx->ctx->ts.threads_running; *want_bytes = 0; return 0; } return prepare_transcode_common(tctx, input_frame_buffer, input_frame_buffer_size, want_bytes); } #endif const char * aften_get_version(void) { #ifdef GIT_VERSION static const char *const str = AFTEN_VERSION "-" GIT_VERSION; #else static const char *const str = AFTEN_VERSION; #endif return str; } static void set_available_simd_instructions(AftenSimdInstructions *simd_instructions) { cpu_caps_detect(); memset(simd_instructions, 0, sizeof(AftenSimdInstructions)); #ifdef HAVE_MMX simd_instructions->mmx = cpu_caps_have_mmx(); #endif #ifdef HAVE_SSE simd_instructions->sse = cpu_caps_have_sse(); #endif #ifdef HAVE_SSE2 simd_instructions->sse2 = cpu_caps_have_sse2(); #endif #ifdef HAVE_SSE3 simd_instructions->sse3 = cpu_caps_have_sse3(); #endif /* Following SIMD code doesn't exist yet, so don't set it available */ #if 0 #ifdef HAVE_SSSE3 simd_instructions->ssse3 = cpu_caps_have_ssse3(); #endif #ifdef HAVE_HAVE_3DNOW simd_instructions->amd_3dnow = cpu_caps_have_3dnow(); #endif #ifdef HAVE_HAVE_SSE_MMX simd_instructions->amd_sse_mmx = cpu_caps_have_sse_mmx(); #endif #ifdef HAVE_HAVE_3DNOWEXT simd_instructions->amd_3dnowext = cpu_caps_have_3dnowext(); #endif #endif #ifdef HAVE_ALTIVEC simd_instructions->altivec = cpu_caps_have_altivec(); #endif } void aften_set_defaults(AftenContext *s) { if (s == NULL) { fprintf(stderr, "NULL parameter passed to aften_set_defaults\n"); return; } /** * These 5 must be set explicitly before initialization. * There are utility functions to help setting acmod and lfe. */ /* Tell the context which SIMD instruction sets are available. */ set_available_simd_instructions(&s->system.available_simd_instructions); s->system.wanted_simd_instructions = s->system.available_simd_instructions; s->system.n_threads = 0; s->verbose = 1; s->channels = -1; s->samplerate = -1; s->acmod = -1; s->lfe = -1; s->mode = AFTEN_ENCODE; s->sample_format = A52_SAMPLE_FMT_S16; s->private_context = NULL; s->params.encoding_mode = AFTEN_ENC_MODE_CBR; s->params.bitrate = 0; s->params.quality = 240; s->params.bwcode = -1; s->params.use_rematrixing = 1; s->params.use_block_switching = 0; s->params.use_bw_filter = 0; s->params.use_dc_filter = 0; s->params.use_lfe_filter = 0; s->params.bitalloc_fast = 0; s->params.expstr_search = 8; s->params.dynrng_profile = DYNRNG_PROFILE_NONE; s->params.min_bwcode = 0; s->params.max_bwcode = 60; s->meta.cmixlev = 0; s->meta.surmixlev = 0; s->meta.dsurmod = 0; s->meta.dialnorm = 31; s->meta.xbsi1e = 0; s->meta.dmixmod = 0; s->meta.ltrtcmixlev = 4; s->meta.ltrtsmixlev = 4; s->meta.lorocmixlev = 4; s->meta.lorosmixlev = 4; s->meta.xbsi2e = 0; s->meta.dsurexmod = 0; s->meta.dheadphonmod = 0; s->meta.adconvtyp = 0; s->status.quality = 0; s->status.bit_rate = 0; s->status.bwcode = 0; s->initial_samples = NULL; } int aften_encode_init(AftenContext *s) { A52Context *ctx; int i, j, brate; int last_quality; if (s == NULL) { fprintf(stderr, "NULL parameter passed to aften_encode_init\n"); return -1; } cpu_caps_detect(); apply_simd_restrictions(&s->system.wanted_simd_instructions); ctx = calloc(sizeof(A52Context), 1); if (!ctx) { fprintf(stderr, "error allocating memory for A52Context\n"); return -1; } mdct_init(ctx); s->private_context = ctx; ctx->params = s->params; ctx->meta = s->meta; a52_common_init(); switch (s->mode) { case AFTEN_TRANSCODE: { fprintf(stderr, "Sorry, trancoding support is not complete, yet."); return -1; #if 0 A52ThreadContext *tctx; if (!s->initial_samples) { fprintf(stderr, "At least one initial frame must be provided via initial_samples when transcoding."); return -1; }//FIXME: must specify amount of bytes ctx->halfratecod = 0; tctx = calloc(sizeof(A52ThreadContext), 1); ctx->tctx = tctx; ctx->tctx->ctx = ctx; tctx->dctx = calloc(sizeof(A52DecodeContext), 1); mdct_thread_init(ctx->tctx); a52_decode_init(); a52_decode_init_thread(ctx->tctx); memcpy(tctx->dctx->input_frame_buffer, s->initial_samples, A52_MAX_CODED_FRAME_SIZE); tctx->dctx->input_frame_buffer_size = A52_MAX_CODED_FRAME_SIZE; a52_decode_frame(ctx->tctx); mdct_thread_close(ctx->tctx); ctx->acmod = tctx->dctx->channel_mode; ctx->lfe = tctx->dctx->lfe_on; ctx->n_channels = tctx->dctx->fbw_channels; ctx->n_all_channels = ctx->n_channels + ctx->lfe; ctx->lfe_channel = s->lfe ? ctx->n_channels : -1; ctx->sample_rate = tctx->dctx->sample_rate; ctx->fscod = tctx->dctx->bit_alloc_params.fscod; ctx->halfratecod = tctx->dctx->bit_alloc_params.halfratecod; ctx->bsid = tctx->dctx->bsid; ctx->bsmod = tctx->dctx->bsmod; ctx->meta.cmixlev = tctx->dctx->cmixlev; ctx->meta.surmixlev = tctx->dctx->surmixlev; ctx->meta.dsurmod = tctx->dctx->dsurmod; a52_decode_deinit_thread(tctx); free(tctx->dctx); free(ctx->tctx); break; #endif } case AFTEN_ENCODE: set_converter(ctx, s->sample_format); // channel configuration if (s->channels < 1 || s->channels > 6) { fprintf(stderr, "invalid number of channels\n"); return -1; } if (s->acmod < 0 || s->acmod > 7) { fprintf(stderr, "invalid acmod\n"); return -1; } if (s->channels == 6 && !s->lfe) { fprintf(stderr, "6-channel audio must have LFE channel\n"); return -1; } if (s->channels == 1 && s->lfe) { fprintf(stderr, "cannot encode stand-alone LFE channel\n"); return -1; } ctx->acmod = s->acmod; ctx->lfe = s->lfe; ctx->n_all_channels = s->channels; ctx->n_channels = s->channels - s->lfe; ctx->lfe_channel = s->lfe ? (s->channels - 1) : -1; // frequency for (i=0;i<3;i++) { for (j=0;j<3;j++) if ((a52_sample_rate_tab[j] >> i) == s->samplerate) goto found; } fprintf(stderr, "invalid sample rate\n"); return -1; found: ctx->sample_rate = s->samplerate; ctx->halfratecod = i; ctx->fscod = j; if (ctx->halfratecod) { // DolbyNet ctx->bsid = 8 + ctx->halfratecod; } else if (ctx->meta.xbsi1e || ctx->meta.xbsi2e) { // alternate bit stream syntax ctx->bsid = 6; } else { // normal AC-3 ctx->bsid = 8; } ctx->bsmod = 0; break; default: fprintf(stderr, "Unknown opertion mode specified.\n"); return -1; } ctx->last_samples_count = -1; // bitrate & frame size brate = s->params.bitrate; if (ctx->params.encoding_mode == AFTEN_ENC_MODE_CBR) { if (brate == 0) { switch (ctx->n_channels) { case 1: brate = 96; break; case 2: brate = 192; break; case 3: brate = 256; break; case 4: brate = 384; break; case 5: brate = 448; break; } } } else if (ctx->params.encoding_mode == AFTEN_ENC_MODE_VBR) { if (s->params.quality < 0 || s->params.quality > 1023) { fprintf(stderr, "invalid quality setting\n"); return -1; } } else { return -1; } for (i = 0; i < 19; i++) { if ((a52_bitrate_tab[i] >> ctx->halfratecod) == brate) break; } if (i == 19) { if (ctx->params.encoding_mode == AFTEN_ENC_MODE_CBR) { fprintf(stderr, "invalid bitrate\n"); return -1; } i = 18; } ctx->frmsizecod = i*2; ctx->target_bitrate = a52_bitrate_tab[i] >> ctx->halfratecod; if (ctx->params.expstr_search < 1 || ctx->params.expstr_search > 32) { fprintf(stderr, "invalid exponent strategy search size: %d\n", ctx->params.expstr_search); return -1; } crc_init(); a52_window_init(&ctx->winf); exponent_init(&ctx->expf); dynrng_init(); last_quality = 240; if (ctx->params.encoding_mode == AFTEN_ENC_MODE_VBR) last_quality = ctx->params.quality; else if (ctx->params.encoding_mode == AFTEN_ENC_MODE_CBR) last_quality = ((((ctx->target_bitrate/ctx->n_channels)*35)/24)+95)+(25*ctx->halfratecod); if (s->params.bwcode < -2 || s->params.bwcode > 60) { fprintf(stderr, "invalid bandwidth code\n"); return -1; } if (ctx->params.bwcode < 0) { int cutoff = ((last_quality-120) * 120) + 4000; ctx->fixed_bwcode = ((cutoff * 512 / ctx->sample_rate) - 73) / 3; if (ctx->params.bwcode == -2) { if (ctx->params.min_bwcode < 0 || ctx->params.min_bwcode > 60 || ctx->params.max_bwcode < 0 || ctx->params.max_bwcode > 60 || ctx->params.min_bwcode > ctx->params.max_bwcode) { fprintf(stderr, "invalid min/max bandwidth code\n"); return -1; } if (ctx->params.encoding_mode == AFTEN_ENC_MODE_VBR) { fprintf(stderr, "variable bandwidth mode cannot be used with variable bitrate mode\n"); return -1; } } ctx->fixed_bwcode = CLIP(ctx->fixed_bwcode, ctx->params.min_bwcode, ctx->params.max_bwcode); } else { ctx->fixed_bwcode = ctx->params.bwcode; } if (s->mode == AFTEN_ENCODE) { // can't do block switching with low sample rate due to the high-pass filter if (ctx->sample_rate <= 16000) ctx->params.use_block_switching = 0; // initialize transient-detect filters (one for each channel) // cascaded biquad direct form I high-pass w/ cutoff of 8 kHz if (ctx->params.use_block_switching) { for (i = 0; i < ctx->n_all_channels; i++) { ctx->bs_filter[i].type = FILTER_TYPE_HIGHPASS; ctx->bs_filter[i].cascaded = 1; ctx->bs_filter[i].cutoff = 8000; ctx->bs_filter[i].samplerate = (FLOAT)ctx->sample_rate; if (filter_init(&ctx->bs_filter[i], FILTER_ID_BIQUAD_I)) { fprintf(stderr, "error initializing transient-detect filter\n"); return -1; } } } // initialize DC filters (one for each channel) // one-pole high-pass w/ cutoff of 3 Hz if (ctx->params.use_dc_filter) { for (i = 0; i < ctx->n_all_channels; i++) { ctx->dc_filter[i].type = FILTER_TYPE_HIGHPASS; ctx->dc_filter[i].cascaded = 0; ctx->dc_filter[i].cutoff = 3; ctx->dc_filter[i].samplerate = (FLOAT)ctx->sample_rate; if (filter_init(&ctx->dc_filter[i], FILTER_ID_ONEPOLE)) { fprintf(stderr, "error initializing dc filter\n"); return -1; } } } // initialize bandwidth filters (one for each channel) // butterworth 2nd order cascaded direct form II low-pass if (ctx->params.use_bw_filter) { int cutoff; int bwcode = ctx->params.bwcode == -2 ? ctx->params.max_bwcode : ctx->fixed_bwcode; cutoff = (((bwcode * 3) + 73) * ctx->sample_rate) / 512; if (cutoff < 4000) { // disable bandwidth filter if cutoff is below 4000 Hz ctx->params.use_bw_filter = 0; } else { for (i = 0; i < ctx->n_channels; i++) { ctx->bw_filter[i].type = FILTER_TYPE_LOWPASS; ctx->bw_filter[i].cascaded = 1; ctx->bw_filter[i].cutoff = (FLOAT)cutoff; ctx->bw_filter[i].samplerate = (FLOAT)ctx->sample_rate; if (filter_init(&ctx->bw_filter[i], FILTER_ID_BUTTERWORTH_II)) { fprintf(stderr, "error initializing bandwidth filter\n"); return -1; } } } } // initialize LFE filter // butterworth 2nd order cascaded direct form II low-pass w/ cutoff of 120 Hz if (ctx->params.use_lfe_filter) { if (!ctx->lfe) { fprintf(stderr, "cannot use lfe filter. no lfe channel\n"); return -1; } ctx->lfe_filter.type = FILTER_TYPE_LOWPASS; ctx->lfe_filter.cascaded = 1; ctx->lfe_filter.cutoff = 120; ctx->lfe_filter.samplerate = (FLOAT)ctx->sample_rate; if (filter_init(&ctx->lfe_filter, FILTER_ID_BUTTERWORTH_II)) { fprintf(stderr, "error initializing lfe filter\n"); return -1; } } } // Initialize thread specific contexts ctx->n_threads = (s->system.n_threads > 0) ? s->system.n_threads : get_ncpus(); ctx->n_threads = MIN(ctx->n_threads, MAX_NUM_THREADS); s->system.n_threads = ctx->n_threads; ctx->tctx = calloc(sizeof(A52ThreadContext), ctx->n_threads); for (j = 0; j < ctx->n_threads; j++) { A52ThreadContext *cur_tctx = &ctx->tctx[j]; cur_tctx->ctx = ctx; cur_tctx->thread_num = j; mdct_thread_init(cur_tctx); cur_tctx->bit_cnt = 0; cur_tctx->sample_cnt = 0; cur_tctx->last_quality = last_quality; if (ctx->n_threads > 1) { cur_tctx->state = START; posix_cond_init(&cur_tctx->ts.enter_cond); posix_cond_init(&cur_tctx->ts.confirm_cond); posix_cond_init(&cur_tctx->ts.samples_cond); posix_mutex_init(&cur_tctx->ts.enter_mutex); posix_mutex_init(&cur_tctx->ts.confirm_mutex); windows_event_init(&cur_tctx->ts.ready_event); windows_event_init(&cur_tctx->ts.enter_event); windows_event_init(&cur_tctx->ts.samples_event); posix_mutex_lock(&cur_tctx->ts.enter_mutex); thread_create(&cur_tctx->ts.thread, threaded_worker, cur_tctx); posix_cond_wait(&cur_tctx->ts.enter_cond, &cur_tctx->ts.enter_mutex); posix_mutex_unlock(&cur_tctx->ts.enter_mutex); windows_event_wait(&cur_tctx->ts.ready_event); windows_event_set(&cur_tctx->ts.ready_event); } } for (j = 0; j < ctx->n_threads; j++) { #ifdef HAVE_POSIX_THREADS ctx->tctx[j].ts.next_samples_cond = &ctx->tctx[(j + 1) % ctx->n_threads].ts.samples_cond; #endif #ifdef HAVE_WINDOWS_THREADS ctx->tctx[j].ts.next_samples_event = &ctx->tctx[(j + 1) % ctx->n_threads].ts.samples_event; #endif } if (ctx->n_threads > 1) { posix_mutex_init(&ctx->ts.samples_mutex); windows_cs_init(&ctx->ts.samples_cs); } switch(s->mode) { case AFTEN_ENCODE: #ifndef NO_THREADS ctx->prepare_work = prepare_encode; #endif ctx->begin_process_frame = begin_encode_frame; // copy initial samples if (s->initial_samples) { FLOAT *samples = malloc(A52_SAMPLES_PER_FRAME * ctx->n_all_channels * sizeof(FLOAT)); memset(samples, 0, (A52_SAMPLES_PER_FRAME - 256) * ctx->n_all_channels * sizeof(FLOAT)); memcpy(samples + (A52_SAMPLES_PER_FRAME - 256) * ctx->n_all_channels, s->initial_samples, 256 * ctx->n_all_channels * sizeof(FLOAT)); convert_samples_from_src(&ctx->tctx[0], samples, A52_SAMPLES_PER_FRAME); free(samples); // copy samples with filters applied // HACK: set threads temporarily to 1 to avoid locking ctx->n_threads = 1; copy_samples(&ctx->tctx[0]); ctx->n_threads = s->system.n_threads; } break; case AFTEN_TRANSCODE: #ifndef NO_THREADS ctx->prepare_work = prepare_transcode; #endif ctx->begin_process_frame = begin_transcode_frame; for (j = 0; j < ctx->n_threads; j++) { A52ThreadContext *tctx = ctx->tctx + j; tctx->dctx = calloc(sizeof(A52DecodeContext), 1); a52_decode_init_thread(tctx); } break; } return 0; } static int frame_init(A52ThreadContext *tctx) { A52Context *ctx = tctx->ctx; A52Frame *frame = &tctx->frame; A52Block *block; int blk, ch; for (blk = 0; blk < A52_NUM_BLOCKS; blk++) { block = &frame->blocks[blk]; block->block_num = blk; for (ch = 0; ch < ctx->n_channels; ch++) { block->blksw[ch] = 0; block->dithflag[ch] = 1; // input_samples will be null if context is not initialized if (block->input_samples[ch] == NULL) return -1; } } if (ctx->params.encoding_mode == AFTEN_ENC_MODE_CBR) { frame->bit_rate = ctx->target_bitrate; frame->frmsizecod = ctx->frmsizecod; frame->frame_size_min = frame->bit_rate * 96000 / ctx->sample_rate; frame->frame_size = frame->frame_size_min; } if (ctx->params.bwcode == -2) frame->bwcode = 60; else frame->bwcode = ctx->fixed_bwcode; for (ch = 0; ch < ctx->n_channels; ch++) frame->ncoefs[ch] = (frame->bwcode * 3) + 73; if (ctx->lfe) frame->ncoefs[ctx->lfe_channel] = 7; frame->frame_bits = 0; frame->exp_bits = 0; frame->mant_bits = 0; // default bit allocation params frame->sdecaycod = 2; frame->fdecaycod = 1; frame->sgaincod = 1; frame->dbkneecod = 2; frame->floorcod = 7; return 0; } /* output the A52 frame header */ static void output_frame_header(A52ThreadContext *tctx, uint8_t *frame_buffer) { A52Context *ctx = tctx->ctx; A52Frame *f = &tctx->frame; BitWriter *bw = &tctx->bw; int frmsizecod = f->frmsizecod+(f->frame_size-f->frame_size_min); bitwriter_init(bw, frame_buffer, A52_MAX_CODED_FRAME_SIZE); bitwriter_writebits(bw, 16, 0x0B77); /* frame header */ bitwriter_writebits(bw, 16, 0); /* crc1: will be filled later */ bitwriter_writebits(bw, 2, ctx->fscod); bitwriter_writebits(bw, 6, frmsizecod); bitwriter_writebits(bw, 5, ctx->bsid); bitwriter_writebits(bw, 3, ctx->bsmod); bitwriter_writebits(bw, 3, ctx->acmod); if ((ctx->acmod & 0x01) && (ctx->acmod != A52_ACMOD_MONO)) bitwriter_writebits(bw, 2, ctx->meta.cmixlev); if (ctx->acmod & 0x04) bitwriter_writebits(bw, 2, ctx->meta.surmixlev); if (ctx->acmod == A52_ACMOD_STEREO) bitwriter_writebits(bw, 2, ctx->meta.dsurmod); bitwriter_writebits(bw, 1, ctx->lfe); bitwriter_writebits(bw, 5, ctx->meta.dialnorm); bitwriter_writebits(bw, 1, 0); /* no compression control word */ bitwriter_writebits(bw, 1, 0); /* no lang code */ bitwriter_writebits(bw, 1, 0); /* no audio production info */ if (ctx->acmod == A52_ACMOD_DUAL_MONO) { bitwriter_writebits(bw, 5, ctx->meta.dialnorm); bitwriter_writebits(bw, 1, 0); /* no compression control word 2 */ bitwriter_writebits(bw, 1, 0); /* no lang code 2 */ bitwriter_writebits(bw, 1, 0); /* no audio production info 2 */ } bitwriter_writebits(bw, 1, 0); /* no copyright */ bitwriter_writebits(bw, 1, 1); /* original bitstream */ if (ctx->bsid == 6) { // alternate bit stream syntax bitwriter_writebits(bw, 1, ctx->meta.xbsi1e); if (ctx->meta.xbsi1e) { bitwriter_writebits(bw, 2, ctx->meta.dmixmod); bitwriter_writebits(bw, 3, ctx->meta.ltrtcmixlev); bitwriter_writebits(bw, 3, ctx->meta.ltrtsmixlev); bitwriter_writebits(bw, 3, ctx->meta.lorocmixlev); bitwriter_writebits(bw, 3, ctx->meta.lorosmixlev); } bitwriter_writebits(bw, 1, ctx->meta.xbsi2e); if (ctx->meta.xbsi2e) { bitwriter_writebits(bw, 2, ctx->meta.dsurexmod); bitwriter_writebits(bw, 2, ctx->meta.dheadphonmod); bitwriter_writebits(bw, 1, ctx->meta.adconvtyp); bitwriter_writebits(bw, 9, 0); } } else { bitwriter_writebits(bw, 1, 0); // timecod1e bitwriter_writebits(bw, 1, 0); // timecod2e } bitwriter_writebits(bw, 1, 0); /* no addtional bit stream info */ } /* symmetric quantization on 'levels' levels */ #define sym_quant(c, e, levels) \ ((((((levels) * (c)) >> (24-(e))) + 1) >> 1) + ((levels) >> 1)) /* asymmetric quantization on 2^qbits levels */ static inline int asym_quant(int c, int e, int qbits) { int lshift, m, v; lshift = e + (qbits-1) - 24; if (lshift >= 0) v = c << lshift; else v = c >> (-lshift); m = (1 << (qbits-1)); v = CLIP(v, -m, m-1); return v; } static void quant_mant_ch(FLOAT *mdct_coef, uint8_t *exp, uint8_t *bap, uint16_t *qmant, int ncoefs, uint16_t *qmant_ptr[3], int mant_cnt[3]) { int i, c, e, b, v; for (i = 0; i < ncoefs; i++) { c = (int)(mdct_coef[i] * (1 << 24)); e = exp[i]; b = bap[i]; switch (b) { case 0: v = 0; break; case 1: v = sym_quant(c, e, 3); if (mant_cnt[0] == 0) { qmant_ptr[0] = &qmant[i]; v = 9 * v; } else if (mant_cnt[0] == 1) { *qmant_ptr[0] += 3 * v; v = 128; } else { *qmant_ptr[0] += v; v = 128; } mant_cnt[0] = (mant_cnt[0] + 1) % 3; break; case 2: v = sym_quant(c, e, 5); if (mant_cnt[1] == 0) { qmant_ptr[1] = &qmant[i]; v = 25 * v; } else if (mant_cnt[1] == 1) { *qmant_ptr[1] += 5 * v; v = 128; } else { *qmant_ptr[1] += v; v = 128; } mant_cnt[1] = (mant_cnt[1] + 1) % 3; break; case 3: v = sym_quant(c, e, 7); break; case 4: v = sym_quant(c, e, 11); if (mant_cnt[2]== 0) { qmant_ptr[2] = &qmant[i]; v = 11 * v; } else { *qmant_ptr[2] += v; v = 128; } mant_cnt[2] = (mant_cnt[2] + 1) % 2; break; case 5: v = sym_quant(c, e, 15); break; case 14: v = asym_quant(c, e, 14); break; case 15: v = asym_quant(c, e, 16); break; default: v = asym_quant(c, e, b - 1); } qmant[i] = v; } } static void quantize_mantissas(A52ThreadContext *tctx) { A52Context *ctx = tctx->ctx; A52Frame *frame = &tctx->frame; A52Block *block; uint16_t *qmant_ptr[3]; int blk, ch; int mant_cnt[3]; for (blk = 0; blk < A52_NUM_BLOCKS; blk++) { block = &frame->blocks[blk]; mant_cnt[0] = mant_cnt[1] = mant_cnt[2] = 0; qmant_ptr[0] = qmant_ptr[1] = qmant_ptr[2] = NULL; for (ch = 0; ch < ctx->n_all_channels; ch++) { quant_mant_ch(block->mdct_coef[ch], block->exp[ch], block->bap[ch], block->qmant[ch], frame->ncoefs[ch], qmant_ptr, mant_cnt); } } } /* Output each audio block. */ static void output_audio_blocks(A52ThreadContext *tctx) { A52Context *ctx = tctx->ctx; A52Frame *frame = &tctx->frame; A52Block *block; BitWriter *bw; int blk, ch, i, baie, rbnd; bw = &tctx->bw; for (blk = 0; blk < A52_NUM_BLOCKS; blk++) { block = &frame->blocks[blk]; for (ch = 0; ch < ctx->n_channels; ch++) bitwriter_writebits(bw, 1, block->blksw[ch]); for (ch = 0; ch < ctx->n_channels; ch++) bitwriter_writebits(bw, 1, block->dithflag[ch]); if (ctx->params.dynrng_profile == DYNRNG_PROFILE_NONE) { bitwriter_writebits(bw, 1, 0); // no dynamic range if (ctx->acmod == A52_ACMOD_DUAL_MONO) bitwriter_writebits(bw, 1, 0); // no dynamic range 2 } else { bitwriter_writebits(bw, 1, 1); bitwriter_writebits(bw, 8, block->dynrng); if (ctx->acmod == A52_ACMOD_DUAL_MONO) { bitwriter_writebits(bw, 1, 1); bitwriter_writebits(bw, 8, block->dynrng); } } if (block->block_num == 0) { // must define coupling strategy in block 0 bitwriter_writebits(bw, 1, 1); // new coupling strategy bitwriter_writebits(bw, 1, 0); // no coupling in use } else { bitwriter_writebits(bw, 1, 0); // no new coupling strategy } if (ctx->acmod == A52_ACMOD_STEREO) { int rematstr = !blk; bitwriter_writebits(bw, 1, rematstr); if (rematstr) { for (rbnd = 0; rbnd < 4; rbnd++) bitwriter_writebits(bw, 1, frame->rematflg[rbnd]); } } // exponent strategy for (ch = 0; ch < ctx->n_channels; ch++) bitwriter_writebits(bw, 2, block->exp_strategy[ch]); if (ctx->lfe) bitwriter_writebits(bw, 1, block->exp_strategy[ctx->lfe_channel]); for (ch = 0; ch < ctx->n_channels; ch++) { if (block->exp_strategy[ch] != EXP_REUSE) bitwriter_writebits(bw, 6, frame->bwcode); } // exponents for (ch = 0; ch < ctx->n_all_channels; ch++) { if (block->exp_strategy[ch] != EXP_REUSE) { // first exponent bitwriter_writebits(bw, 4, block->grp_exp[ch][0]); // delta-encoded exponent groups for (i = 1; i <= block->nexpgrps[ch]; i++) bitwriter_writebits(bw, 7, block->grp_exp[ch][i]); // gain range info if (ch != ctx->lfe_channel) bitwriter_writebits(bw, 2, 0); } } // bit allocation info baie = (block->block_num == 0); bitwriter_writebits(bw, 1, baie); if (baie) { bitwriter_writebits(bw, 2, frame->sdecaycod); bitwriter_writebits(bw, 2, frame->fdecaycod); bitwriter_writebits(bw, 2, frame->sgaincod); bitwriter_writebits(bw, 2, frame->dbkneecod); bitwriter_writebits(bw, 3, frame->floorcod); } // snr offset bitwriter_writebits(bw, 1, block->write_snr); if (block->write_snr) { bitwriter_writebits(bw, 6, frame->csnroffst); for (ch = 0; ch < ctx->n_all_channels; ch++) { bitwriter_writebits(bw, 4, frame->fsnroffst); bitwriter_writebits(bw, 3, block->fgaincod[ch]); } } bitwriter_writebits(bw, 1, 0); // no delta bit allocation bitwriter_writebits(bw, 1, 0); // no data to skip // mantissas for (ch = 0; ch < ctx->n_all_channels; ch++) { int b, q; for (i = 0; i < frame->ncoefs[ch]; i++) { q = block->qmant[ch][i]; b = block->bap[ch][i]; switch (b) { case 0: break; case 1: if(q != 128) bitwriter_writebits(bw, 5, q); break; case 2: if(q != 128) bitwriter_writebits(bw, 7, q); break; case 3: bitwriter_writebits(bw, 3, q); break; case 4: if(q != 128) bitwriter_writebits(bw, 7, q); break; case 14: bitwriter_writebits(bw, 14, q); break; case 15: bitwriter_writebits(bw, 16, q); break; default: bitwriter_writebits(bw, b - 1, q); } } } } } static int output_frame_end(A52ThreadContext *tctx) { uint8_t *frame; int fs, fs58, n, crc1, crc2, bitcount; fs = tctx->frame.frame_size; // align to 8 bits bitwriter_flushbits(&tctx->bw); // add zero bytes to reach the frame size frame = tctx->bw.buffer; bitcount = bitwriter_bitcount(&tctx->bw); n = (fs << 1) - 2 - (bitcount >> 3); if (n < 0) { fprintf(stderr, "data size exceeds frame size (frame=%d data=%d)\n", (fs << 1) - 2, bitcount >> 3); return -1; } if (n > 0) memset(&tctx->bw.buffer[bitcount>>3], 0, n); // compute crc1 for 1st 5/8 of frame fs58 = (fs >> 1) + (fs >> 3); crc1 = calc_crc16(&frame[4], (fs58<<1)-4); crc1 = crc16_zero(crc1, (fs58<<1)-2); frame[2] = crc1 >> 8; frame[3] = crc1; // double-check crc1 = calc_crc16(&frame[2], (fs58<<1)-2); if (crc1 != 0) fprintf(stderr, "CRC ERROR\n"); // compute crc2 for final 3/8 of frame crc2 = calc_crc16(&frame[fs58<<1], ((fs - fs58) << 1) - 2); frame[(fs<<1)-2] = crc2 >> 8; frame[(fs<<1)-1] = crc2; return (fs << 1); } static void copy_samples(A52ThreadContext *tctx) { A52Context *ctx = tctx->ctx; A52Frame *frame = &tctx->frame; FLOAT buffer[A52_SAMPLES_PER_FRAME]; FLOAT *in_audio; FLOAT *out_audio; FLOAT *temp; int ch, blk; #define SWAP_BUFFERS temp=in_audio;in_audio=out_audio;out_audio=temp; #ifndef NO_THREADS if (ctx->n_threads > 1) { posix_mutex_lock(&ctx->ts.samples_mutex); windows_cs_enter(&ctx->ts.samples_cs); while (ctx->ts.samples_thread_num != tctx->thread_num) { posix_cond_wait(&tctx->ts.samples_cond, &ctx->ts.samples_mutex); windows_cs_leave(&ctx->ts.samples_cs); windows_event_wait(&tctx->ts.samples_event); windows_cs_enter(&ctx->ts.samples_cs); } windows_event_reset(&tctx->ts.samples_event); } #endif for (ch = 0; ch < ctx->n_all_channels; ch++) { out_audio = buffer; in_audio = frame->input_audio[ch]; // DC-removal high-pass filter if (ctx->params.use_dc_filter) { filter_run(&ctx->dc_filter[ch], out_audio, in_audio, A52_SAMPLES_PER_FRAME); SWAP_BUFFERS } if (ch < ctx->n_channels) { // channel bandwidth filter if (ctx->params.use_bw_filter) { filter_run(&ctx->bw_filter[ch], out_audio, in_audio, A52_SAMPLES_PER_FRAME); SWAP_BUFFERS } // block-switching high-pass filter if (ctx->params.use_block_switching) { filter_run(&ctx->bs_filter[ch], out_audio, in_audio, A52_SAMPLES_PER_FRAME); memcpy(frame->blocks[0].transient_samples[ch], ctx->last_transient_samples[ch], 256 * sizeof(FLOAT)); memcpy(&frame->blocks[0].transient_samples[ch][256], out_audio, 256 * sizeof(FLOAT)); for (blk = 1; blk < A52_NUM_BLOCKS; blk++) { memcpy(frame->blocks[blk].transient_samples[ch], &out_audio[256*(blk-1)], 512 * sizeof(FLOAT)); } memcpy(ctx->last_transient_samples[ch], &out_audio[256*5], 256 * sizeof(FLOAT)); } } else { // LFE bandwidth low-pass filter if (ctx->params.use_lfe_filter) { assert(ch == ctx->lfe_channel); filter_run(&ctx->lfe_filter, out_audio, in_audio, A52_SAMPLES_PER_FRAME); SWAP_BUFFERS } } memcpy(frame->blocks[0].input_samples[ch], ctx->last_samples[ch], 256 * sizeof(FLOAT)); memcpy(&frame->blocks[0].input_samples[ch][256], in_audio, 256 * sizeof(FLOAT)); for (blk = 1; blk < A52_NUM_BLOCKS; blk++) { memcpy(frame->blocks[blk].input_samples[ch], &in_audio[256*(blk-1)], 512 * sizeof(FLOAT)); } memcpy(ctx->last_samples[ch], &in_audio[256*5], 256 * sizeof(FLOAT)); } #ifndef NO_THREADS if (ctx->n_threads > 1) { ++ctx->ts.samples_thread_num; ctx->ts.samples_thread_num %= ctx->n_threads; posix_cond_signal(tctx->ts.next_samples_cond); posix_mutex_unlock(&ctx->ts.samples_mutex); windows_event_set(tctx->ts.next_samples_event); windows_cs_leave(&ctx->ts.samples_cs); } #endif #undef SWAP_BUFFERS } /* determines block length by detecting transients */ static int detect_transient(FLOAT *in) { FLOAT *xx = in; int i, j; FLOAT level1[2]; FLOAT level2[4]; FLOAT level3[8]; FLOAT tmax = FCONST(100.0) / FCONST(32768.0); FLOAT t1 = FCONST(0.100); FLOAT t2 = FCONST(0.075); FLOAT t3 = FCONST(0.050); // level 1 (2 x 256) for (i = 0; i < 2; i++) { level1[i] = 0; for (j = 0; j < 256; j++) level1[i] = MAX(AFT_FABS(xx[i*256+j]), level1[i]); if (level1[i] < tmax) return 0; if ((i > 0) && (level1[i] * t1 > level1[i-1])) return 1; } // level 2 (4 x 128) for (i = 1; i < 4; i++) { level2[i] = 0; for (j = 0; j < 128; j++) level2[i] = MAX(AFT_FABS(xx[i*128+j]), level2[i]); if ((i > 1) && (level2[i] * t2 > level2[i-1])) return 1; } // level 3 (8 x 64) for (i = 3; i < 8; i++) { level3[i] = 0; for (j = 0; j < 64; j++) level3[i] = MAX(AFT_FABS(xx[i*64+j]), level3[i]); if ((i > 3) && (level3[i] * t3 > level3[i-1])) return 1; } return 0; } static void generate_coefs(A52ThreadContext *tctx) { A52Context *ctx = tctx->ctx; A52Block *block; void (*mdct_256)(struct A52ThreadContext *tctx, FLOAT *out, FLOAT *in) = ctx->mdct_ctx_256.mdct; void (*mdct_512)(struct A52ThreadContext *tctx, FLOAT *out, FLOAT *in) = ctx->mdct_ctx_512.mdct; int blk, ch, i; for (ch = 0; ch < ctx->n_all_channels; ch++) { for (blk = 0; blk < A52_NUM_BLOCKS; blk++) { block = &tctx->frame.blocks[blk]; if (ctx->params.use_block_switching) block->blksw[ch] = detect_transient(block->transient_samples[ch]); else block->blksw[ch] = 0; ctx->winf.apply_a52_window(block->input_samples[ch]); if (block->blksw[ch]) mdct_256(tctx, block->mdct_coef[ch], block->input_samples[ch]); else mdct_512(tctx, block->mdct_coef[ch], block->input_samples[ch]); for (i = tctx->frame.ncoefs[ch]; i < 256; i++) block->mdct_coef[ch][i] = 0.0; } } } static void calc_rematrixing(A52ThreadContext *tctx) { A52Context *ctx = tctx->ctx; A52Frame *frame = &tctx->frame; A52Block *block; FLOAT sum[4][4]; FLOAT lt, rt, ctmp1, ctmp2; int blk, bnd, i; // initialize flags to zero for (bnd = 0; bnd < 4; bnd++) frame->rematflg[bnd] = 0; // if rematrixing is disabled, return if (!ctx->params.use_rematrixing) return; // calculate rematrixing flags and apply rematrixing to coefficients for (bnd = 0; bnd < 4; bnd++) { // calculate sums for this band for all blocks sum[bnd][0] = sum[bnd][1] = sum[bnd][2] = sum[bnd][3] = 0; for (blk = 0; blk < A52_NUM_BLOCKS; blk++) { block = &frame->blocks[blk]; for (i = rematbndtab[bnd]; i < rematbndtab[bnd+1]; i++) { if (i == frame->ncoefs[0]) break; lt = block->mdct_coef[0][i]; rt = block->mdct_coef[1][i]; sum[bnd][0] += lt * lt; sum[bnd][1] += rt * rt; sum[bnd][2] += (lt + rt) * (lt + rt) / FCONST(4.0); sum[bnd][3] += (lt - rt) * (lt - rt) / FCONST(4.0); } } // compare sums to determine if rematrixing is used for this band if (sum[bnd][0]+sum[bnd][1] > (sum[bnd][2]+sum[bnd][3])/2.0) { frame->rematflg[bnd] = 1; // apply rematrixing in this band for all blocks for (blk = 0; blk < A52_NUM_BLOCKS; blk++) { block = &frame->blocks[blk]; for (i = rematbndtab[bnd]; i < rematbndtab[bnd+1]; i++) { if (i == frame->ncoefs[0]) break; ctmp1 = block->mdct_coef[0][i] * FCONST(0.5); ctmp2 = block->mdct_coef[1][i] * FCONST(0.5); block->mdct_coef[0][i] = ctmp1 + ctmp2; block->mdct_coef[1][i] = ctmp1 - ctmp2; } } } } } /** Adjust for fractional frame sizes in CBR mode */ static void adjust_frame_size(A52ThreadContext *tctx) { A52Context *ctx = tctx->ctx; A52Frame *f = &tctx->frame; uint32_t kbps = f->bit_rate * 1000; uint32_t srate = ctx->sample_rate; int add; while (tctx->bit_cnt >= kbps && tctx->sample_cnt >= srate) { tctx->bit_cnt -= kbps; tctx->sample_cnt -= srate; } add = !!(tctx->bit_cnt * srate < tctx->sample_cnt * kbps); f->frame_size = f->frame_size_min + add; } static void compute_dither_strategy(A52ThreadContext *tctx) { A52Block *block0; A52Block *block1; int channels = tctx->ctx->n_channels; int blk, ch; block0 = NULL; for (blk = 0; blk < A52_NUM_BLOCKS; blk++) { block1 = &tctx->frame.blocks[blk]; for (ch = 0; ch < channels; ch++) { if (block1->blksw[ch] || ((blk>0) && block0->blksw[ch])) block1->dithflag[ch] = 0; else block1->dithflag[ch] = 1; } block0 = block1; } } static void calculate_dynrng(A52ThreadContext *tctx) { A52Context *ctx = tctx->ctx; A52Block *block; int blk; if (ctx->params.dynrng_profile == DYNRNG_PROFILE_NONE) return; for (blk = 0; blk < A52_NUM_BLOCKS; blk++) { block = &tctx->frame.blocks[blk]; block->dynrng = calculate_block_dynrng(block->input_samples, ctx->n_all_channels, -ctx->meta.dialnorm, ctx->params.dynrng_profile); } } static int begin_transcode_frame(A52ThreadContext *tctx) { return -(a52_decode_frame(tctx) <= 0); } static int begin_encode_frame(A52ThreadContext *tctx) { copy_samples(tctx); calculate_dynrng(tctx); generate_coefs(tctx); return 0; } static int process_frame(A52ThreadContext *tctx, uint8_t *output_frame_buffer) { A52Context *ctx = tctx->ctx; A52Frame *frame = &tctx->frame; if (frame_init(tctx)) { fprintf(stderr, "Encoding has not properly initialized\n"); return -1; } if (ctx->begin_process_frame(tctx)) return -1; compute_dither_strategy(tctx); if (ctx->acmod == A52_ACMOD_STEREO) calc_rematrixing(tctx); // variable bandwidth if (ctx->params.bwcode == -2) { // process exponents at full bandwidth a52_process_exponents(tctx); // run bit allocation at q=240 to calculate bandwidth vbw_bit_allocation(tctx); } a52_process_exponents(tctx); if (ctx->params.encoding_mode == AFTEN_ENC_MODE_CBR) adjust_frame_size(tctx); if (compute_bit_allocation(tctx)) { fprintf(stderr, "Error in bit allocation\n"); tctx->framesize = 0; return -1; } quantize_mantissas(tctx); // increment counters tctx->bit_cnt += frame->frame_size * 16; tctx->sample_cnt += A52_SAMPLES_PER_FRAME; // update encoding status tctx->status.quality = frame->quality; tctx->status.bit_rate = frame->bit_rate; tctx->status.bwcode = frame->bwcode; output_frame_header(tctx, output_frame_buffer); output_audio_blocks(tctx); tctx->framesize = output_frame_end(tctx); return 0; } static int convert_samples_from_src(A52ThreadContext *tctx, const void *vsrc, int count) { A52Context *ctx = tctx->ctx; ctx->fmt_convert_from_src(tctx->frame.input_audio, vsrc, ctx->n_all_channels, count); if (count < A52_SAMPLES_PER_FRAME) { int ch; for (ch = 0; ch < ctx->n_all_channels; ch++) memset(&tctx->frame.input_audio[ch][count], 0, (A52_SAMPLES_PER_FRAME - count) * sizeof(FLOAT)); } return 0; } #ifndef NO_THREADS static int threaded_worker(void* vtctx) { A52ThreadContext *tctx; #ifdef MINGW_ALIGN_STACK_HACK asm volatile ( "movl %%esp, %%ecx\n" "andl $15, %%ecx\n" "subl %%ecx, %%esp\n" "pushl %%ecx\n" "pushl %%ecx\n" "pushl %%ecx\n" "pushl %%ecx\n" : : : "%esp","%ecx"); #endif tctx = vtctx; ++tctx->ctx->ts.threads_running;//no need to lock, as thread creater waits posix_mutex_lock(&tctx->ts.enter_mutex); posix_cond_signal(&tctx->ts.enter_cond); while (1) { posix_cond_wait(&tctx->ts.enter_cond, &tctx->ts.enter_mutex); posix_mutex_lock(&tctx->ts.confirm_mutex); posix_cond_signal(&tctx->ts.confirm_cond); posix_mutex_unlock(&tctx->ts.confirm_mutex); windows_event_set(&tctx->ts.ready_event); windows_event_wait(&tctx->ts.enter_event); /* end thread if nothing to encode */ if (tctx->state == END) { tctx->framesize = 0; break; } if (tctx->state == ABORT) { tctx->framesize = -1; break; } if (process_frame(tctx, tctx->frame_buffer)) tctx->state = ABORT; } posix_mutex_unlock(&tctx->ts.enter_mutex); windows_event_set(&tctx->ts.ready_event); #ifdef MINGW_ALIGN_STACK_HACK asm volatile ( "popl %%ecx\n" "popl %%ecx\n" "popl %%ecx\n" "popl %%ecx\n" "addl %%ecx, %%esp\n" : : : "%esp", "%ecx"); #endif return 0; } static int process_frame_parallel(AftenContext *s, uint8_t *frame_buffer, const void *samples, int count, int *info) { A52Context *ctx = s->private_context; int framesize = 0; if (!ctx->ts.threads_running) return 0; do { A52ThreadContext *tctx = &ctx->tctx[ctx->ts.current_thread_num]; posix_mutex_lock(&tctx->ts.enter_mutex); windows_event_wait(&tctx->ts.ready_event); if (tctx->state == ABORT || ctx->ts.threads_to_abort) { tctx->state = ABORT; framesize = -1; if (!ctx->ts.threads_to_abort) ctx->ts.threads_to_abort = ctx->ts.threads_running; --ctx->ts.threads_to_abort; --ctx->ts.threads_running; } else { if (ctx->prepare_work(tctx, samples, count, info)) { // need more data posix_mutex_unlock(&tctx->ts.enter_mutex); return -1; } if (tctx->state == START) { tctx->state = WORK; } else { if (tctx->framesize > 0) { framesize = tctx->framesize; memcpy(frame_buffer, tctx->frame_buffer, framesize); // update encoding status s->status.quality = tctx->status.quality; s->status.bit_rate = tctx->status.bit_rate; s->status.bwcode = tctx->status.bwcode; } else { posix_mutex_unlock(&tctx->ts.enter_mutex); goto end; } } } posix_mutex_lock(&tctx->ts.confirm_mutex); posix_cond_signal(&tctx->ts.enter_cond); posix_mutex_unlock(&tctx->ts.enter_mutex); posix_cond_wait(&tctx->ts.confirm_cond, &tctx->ts.confirm_mutex); posix_mutex_unlock(&tctx->ts.confirm_mutex); windows_event_set(&tctx->ts.enter_event); end: ++ctx->ts.current_thread_num; ctx->ts.current_thread_num %= ctx->n_threads; } while (ctx->ts.threads_to_abort); return framesize; } #endif #if 0 int aften_transcode_frame(AftenContext *s, uint8_t *input_frame_buffer, int input_frame_buffer_size, uint8_t *output_frame_buffer, int* want_bytes) { A52Context *ctx; A52ThreadContext *tctx; ctx = s->private_context; #ifndef NO_THREADS if (ctx->n_threads > 1) return process_frame_parallel(s, output_frame_buffer, input_frame_buffer, input_frame_buffer_size, want_bytes); #endif if (!input_frame_buffer_size) return 0; tctx = ctx->tctx; if (prepare_transcode_common(tctx, input_frame_buffer, input_frame_buffer_size, want_bytes)) return -1; process_frame(tctx, output_frame_buffer); s->status.quality = tctx->status.quality; s->status.bit_rate = tctx->status.bit_rate; s->status.bwcode = tctx->status.bwcode; return tctx->framesize; } #endif int aften_encode_frame(AftenContext *s, uint8_t *frame_buffer, const void *samples, int count) { A52Context *ctx; A52ThreadContext *tctx; if (s == NULL || frame_buffer == NULL || (samples == NULL && count)) { fprintf(stderr, "One or more NULL parameters passed to aften_encode_frame\n"); return -1; } if (count > A52_SAMPLES_PER_FRAME || count < 0) { fprintf(stderr, "Invalid count passed to aften_encode_frame\n"); return -1; } ctx = s->private_context; if (count && ctx->last_samples_count != -1 && ctx->last_samples_count < A52_SAMPLES_PER_FRAME) { fprintf(stderr, "count must be 0 after having once been n_threads > 1) { int info; return process_frame_parallel(s, frame_buffer, samples, count, &info); } #endif // append extra silent frame if final frame is > 1280 samples, to flush 256 samples in mdct if (ctx->last_samples_count <= (A52_SAMPLES_PER_FRAME - 256) && ctx->last_samples_count != -1) return 0; tctx = ctx->tctx; convert_samples_from_src(tctx, samples, count); process_frame(tctx, frame_buffer); ctx->last_samples_count = count; s->status.quality = tctx->status.quality; s->status.bit_rate = tctx->status.bit_rate; s->status.bwcode = tctx->status.bwcode; return tctx->framesize; } int aften_encode_close(AftenContext *s) { int ch; int ret_val = 0; if (s != NULL && s->private_context != NULL) { A52Context *ctx = s->private_context; #ifndef NO_THREADS while (ctx->ts.threads_running) { uint8_t frame_buffer[A52_MAX_CODED_FRAME_SIZE]; int info; process_frame_parallel(s, frame_buffer, NULL, 0, &info); ret_val = -1; } #endif if (ctx->tctx) { if (ctx->n_threads == 1) mdct_thread_close(&ctx->tctx[0]); else { int i; for (i = 0; i < ctx->n_threads; i++) { A52ThreadContext *cur_tctx = ctx->tctx + i; thread_join(cur_tctx->ts.thread); mdct_thread_close(cur_tctx); posix_cond_destroy(&cur_tctx->ts.enter_cond); posix_cond_destroy(&cur_tctx->ts.confirm_cond); posix_cond_destroy(&cur_tctx->ts.samples_cond); posix_mutex_destroy(&cur_tctx->ts.enter_mutex); posix_mutex_destroy(&cur_tctx->ts.confirm_mutex); windows_event_destroy(&cur_tctx->ts.ready_event); windows_event_destroy(&cur_tctx->ts.enter_event); windows_event_destroy(&cur_tctx->ts.samples_event); } posix_mutex_destroy(&ctx->ts.samples_mutex); windows_cs_destroy(&ctx->ts.samples_cs); } if (s->mode == AFTEN_TRANSCODE) { int i; for (i = 0; i < ctx->n_threads; i++) { A52ThreadContext *cur_tctx = ctx->tctx + i; a52_decode_deinit_thread(cur_tctx); free(cur_tctx->dctx); } } free(ctx->tctx); } // mdct_close deinits both mdcts mdct_close(ctx); // close input filters filter_close(&ctx->lfe_filter); for (ch = 0; ch < A52_MAX_CHANNELS; ch++) { filter_close(&ctx->bs_filter[ch]); filter_close(&ctx->dc_filter[ch]); filter_close(&ctx->bw_filter[ch]); } free(ctx); s->private_context = NULL; } return ret_val; } aften/libaften/a52enc.h000066400000000000000000000055551132016273200151740ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * Copyright (c) 2006 Justin Ruggles * * Based on "The simplest AC3 encoder" from FFmpeg * Copyright (c) 2000 Fabrice Bellard. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file a52.h * A/52 encoder header */ #ifndef A52ENC_H #define A52ENC_H #include "common.h" #include "a52.h" #include "bitio.h" #include "aften.h" #include "exponent.h" #include "filter.h" #include "mdct.h" #include "threading.h" #include "window.h" #include "a52dec.h" typedef struct A52ThreadContext { struct A52Context *ctx; A52DecodeContext *dctx; #ifndef NO_THREADS A52ThreadSync ts; #endif ThreadState state; int thread_num; int framesize; AftenStatus status; A52Frame frame; BitWriter bw; uint8_t frame_buffer[A52_MAX_CODED_FRAME_SIZE]; uint32_t bit_cnt; uint32_t sample_cnt; int last_quality; MDCTThreadContext mdct_tctx_512; MDCTThreadContext mdct_tctx_256; } A52ThreadContext; typedef struct A52Context { A52ThreadContext *tctx; #ifndef NO_THREADS A52GlobalThreadSync ts; int (*prepare_work)(A52ThreadContext *tctx, const void *input_buffer, int count, int *info); #endif int (*begin_process_frame)(A52ThreadContext *tctx); AftenEncParams params; AftenMetadata meta; void (*fmt_convert_from_src)(FLOAT dest[A52_MAX_CHANNELS][A52_SAMPLES_PER_FRAME], const void *vsrc, int nch, int n); A52WindowFunctions winf; A52ExponentFunctions expf; int n_threads; int last_samples_count; int n_channels; int n_all_channels; int acmod; int lfe; int lfe_channel; int sample_rate; int halfratecod; int bsid; int fscod; int bsmod; int target_bitrate; int frmsizecod; int fixed_bwcode; FilterContext bs_filter[A52_MAX_CHANNELS]; FilterContext dc_filter[A52_MAX_CHANNELS]; FilterContext bw_filter[A52_MAX_CHANNELS]; FilterContext lfe_filter; FLOAT last_samples[A52_MAX_CHANNELS][A52_SAMPLES_PER_FRAME]; // 256 would be enough, but want to use converting functions FLOAT last_transient_samples[A52_MAX_CHANNELS][256]; MDCTContext mdct_ctx_512; MDCTContext mdct_ctx_256; } A52Context; #endif /* A52ENC_H */ aften/libaften/a52tab.c000066400000000000000000000214051132016273200151600ustar00rootroot00000000000000/** * Aften: A/52 audio encoder - A/52 tables * Copyright (c) 2008 Prakash Punnoor * * Based on "The simplest AC3 encoder" from FFmpeg * Copyright (c) 2000 Fabrice Bellard. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file a52tab.c * tables taken from ATSC A/52 spec. */ #include "a52tab.h" #include "a52.h" /** * Possible frame sizes in bits * derived from ATSC A/52 Table 5.18 Frame Size Code Table. */ const uint16_t a52_frame_size_tab[38][3] = { { 1024, 1104, 1536}, { 1024, 1120, 1536}, { 1280, 1392, 1920}, { 1280, 1408, 1920}, { 1536, 1664, 2304}, { 1536, 1680, 2304}, { 1792, 1936, 2688}, { 1792, 1952, 2688}, { 2048, 2224, 3072}, { 2048, 2240, 3072}, { 2560, 2784, 3840}, { 2560, 2800, 3840}, { 3072, 3328, 4608}, { 3072, 3344, 4608}, { 3584, 3888, 5376}, { 3584, 3904, 5376}, { 4096, 4448, 6144}, { 4096, 4464, 6144}, { 5120, 5568, 7680}, { 5120, 5584, 7680}, { 6144, 6672, 9216}, { 6144, 6688, 9216}, { 7168, 7792, 10752}, { 7168, 7808, 10752}, { 8192, 8912, 12288}, { 8192, 8928, 12288}, {10240, 11136, 15360}, {10240, 11152, 15360}, {12288, 13360, 18432}, {12288, 13376, 18432}, {14336, 15600, 21504}, {14336, 15616, 21504}, {16384, 17824, 24576}, {16384, 17840, 24576}, {18432, 20048, 27648}, {18432, 20064, 27648}, {20480, 22288, 30720}, {20480, 22304, 30720} }; /** * Maps audio coding mode (acmod) to number of full-bandwidth channels. * from ATSC A/52 Table 5.8 Audio Coding Mode */ const uint8_t a52_channels_tab[8] = { 2, 1, 2, 3, 3, 4, 4, 5 }; /* possible frequencies */ const uint16_t a52_sample_rate_tab[3] = { 48000, 44100, 32000 }; /* possible bitrates */ const uint16_t a52_bitrate_tab[19] = { 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 448, 512, 576, 640 }; /** * log addition table */ const uint8_t a52_log_add_tab[260]= { 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 52, 51, 50, 49, 48, 47, 47, 46, 45, 44, 44, 43, 42, 41, 41, 40, 39, 38, 38, 37, 36, 36, 35, 35, 34, 33, 33, 32, 32, 31, 30, 30, 29, 29, 28, 28, 27, 27, 26, 26, 25, 25, 24, 24, 23, 23, 22, 22, 21, 21, 21, 20, 20, 19, 19, 19, 18, 18, 18, 17, 17, 17, 16, 16, 16, 15, 15, 15, 14, 14, 14, 13, 13, 13, 13, 12, 12, 12, 12, 11, 11, 11, 11, 10, 10, 10, 10, 10, 9, 9, 9, 9, 9, 8, 8, 8, 8, 8, 8, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /** * absolute hearing threshold table * values are in log-psd units (128 psd = -6dB) * each table entry corresponds to a critical frequency band * each entry has 3 values, 1 for each base sample rate * { 48kHz, 44.1kHz, 32kHz } */ const uint16_t a52_hearing_threshold_tab[50][3]= { { 1232, 1264, 1408 }, { 1232, 1264, 1408 }, { 1088, 1120, 1200 }, { 1024, 1040, 1104 }, { 992, 992, 1056 }, { 960, 976, 1008 }, { 944, 960, 992 }, { 944, 944, 976 }, { 928, 944, 960 }, { 928, 928, 944 }, { 928, 928, 944 }, { 928, 928, 944 }, { 928, 928, 928 }, { 912, 928, 928 }, { 912, 912, 928 }, { 912, 912, 928 }, { 896, 912, 928 }, { 896, 896, 928 }, { 880, 896, 928 }, { 880, 896, 928 }, { 864, 880, 912 }, { 864, 880, 912 }, { 848, 864, 912 }, { 848, 864, 912 }, { 832, 848, 896 }, { 832, 848, 896 }, { 816, 832, 896 }, { 800, 832, 880 }, { 784, 800, 864 }, { 768, 784, 848 }, { 752, 768, 832 }, { 752, 752, 816 }, { 752, 752, 800 }, { 752, 752, 784 }, { 768, 752, 768 }, { 784, 768, 752 }, { 832, 800, 752 }, { 912, 848, 752 }, { 992, 912, 768 }, { 1056, 992, 784 }, { 1120, 1056, 816 }, { 1168, 1104, 848 }, { 1184, 1184, 960 }, { 1120, 1168, 1040 }, { 1088, 1120, 1136 }, { 1088, 1088, 1184 }, { 1312, 1152, 1120 }, { 2048, 1584, 1088 }, { 2112, 2112, 1104 }, { 2112, 2112, 1248 }, }; /** * bit allocation pointer table */ const uint8_t a52_bap_tab[64]= { 0, 1, 1, 1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, }; /** * slow decay table */ const uint8_t a52_slow_decay_tab[4]={ 15, 17, 19, 21 }; /** * fast decay table */ const uint8_t a52_fast_decay_tab[4]={ 63, 83, 103, 123 }; /** * slow gain table */ const uint16_t a52_slow_gain_tab[4]= { 1344, 1240, 1144, 1040 }; /** * dB per bit table */ const uint16_t a52_db_per_bit_tab[4]= { 0, 1792, 2304, 2816 }; /** * floor table */ const int16_t a52_floor_tab[8]= { 752, 688, 624, 560, 496, 368, 240, -2048 }; /** * fast gain table */ const uint16_t a52_fast_gain_tab[8]= { 128, 256, 384, 512, 640, 768, 896, 1024 }; /** * band size table (number of bins in each band) */ const uint8_t a52_critical_band_size_tab[50]={ 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, 3, 3, 3, 3, 3, 3, 3, 6, 6, 6, 6, 6, 6, 12, 12, 12, 12, 24, 24, 24, 24, 24 }; /** * Pre-defined sets of exponent strategies. A strategy set is selected for * each channel in a frame. */ const uint8_t a52_expstr_set_tab[32][6] = { { EXP_D15, EXP_REUSE, EXP_REUSE, EXP_REUSE, EXP_REUSE, EXP_REUSE }, { EXP_D15, EXP_REUSE, EXP_REUSE, EXP_REUSE, EXP_REUSE, EXP_D45 }, { EXP_D15, EXP_REUSE, EXP_REUSE, EXP_REUSE, EXP_D25, EXP_REUSE }, { EXP_D15, EXP_REUSE, EXP_REUSE, EXP_REUSE, EXP_D45, EXP_D45 }, { EXP_D25, EXP_REUSE, EXP_REUSE, EXP_D25, EXP_REUSE, EXP_REUSE }, { EXP_D25, EXP_REUSE, EXP_REUSE, EXP_D25, EXP_REUSE, EXP_D45 }, { EXP_D25, EXP_REUSE, EXP_REUSE, EXP_D45, EXP_D25, EXP_REUSE }, { EXP_D25, EXP_REUSE, EXP_REUSE, EXP_D45, EXP_D45, EXP_D45 }, { EXP_D25, EXP_REUSE, EXP_D15, EXP_REUSE, EXP_REUSE, EXP_REUSE }, { EXP_D25, EXP_REUSE, EXP_D25, EXP_REUSE, EXP_REUSE, EXP_D45 }, { EXP_D25, EXP_REUSE, EXP_D25, EXP_REUSE, EXP_D25, EXP_REUSE }, { EXP_D25, EXP_REUSE, EXP_D25, EXP_REUSE, EXP_D45, EXP_D45 }, { EXP_D25, EXP_REUSE, EXP_D45, EXP_D25, EXP_REUSE, EXP_REUSE }, { EXP_D25, EXP_REUSE, EXP_D45, EXP_D25, EXP_REUSE, EXP_D45 }, { EXP_D25, EXP_REUSE, EXP_D45, EXP_D45, EXP_D25, EXP_REUSE }, { EXP_D25, EXP_REUSE, EXP_D45, EXP_D45, EXP_D45, EXP_D45 }, { EXP_D45, EXP_D15, EXP_REUSE, EXP_REUSE, EXP_REUSE, EXP_REUSE }, { EXP_D45, EXP_D15, EXP_REUSE, EXP_REUSE, EXP_REUSE, EXP_D45 }, { EXP_D45, EXP_D25, EXP_REUSE, EXP_REUSE, EXP_D25, EXP_REUSE }, { EXP_D45, EXP_D25, EXP_REUSE, EXP_REUSE, EXP_D45, EXP_D45 }, { EXP_D45, EXP_D25, EXP_REUSE, EXP_D25, EXP_REUSE, EXP_REUSE }, { EXP_D45, EXP_D25, EXP_REUSE, EXP_D25, EXP_REUSE, EXP_D45 }, { EXP_D45, EXP_D25, EXP_REUSE, EXP_D45, EXP_D25, EXP_REUSE }, { EXP_D45, EXP_D25, EXP_REUSE, EXP_D45, EXP_D45, EXP_D45 }, { EXP_D45, EXP_D45, EXP_D15, EXP_REUSE, EXP_REUSE, EXP_REUSE }, { EXP_D45, EXP_D45, EXP_D25, EXP_REUSE, EXP_REUSE, EXP_D45 }, { EXP_D45, EXP_D45, EXP_D25, EXP_REUSE, EXP_D25, EXP_REUSE }, { EXP_D45, EXP_D45, EXP_D25, EXP_REUSE, EXP_D45, EXP_D45 }, { EXP_D45, EXP_D45, EXP_D45, EXP_D25, EXP_REUSE, EXP_REUSE }, { EXP_D45, EXP_D45, EXP_D45, EXP_D25, EXP_REUSE, EXP_D45 }, { EXP_D45, EXP_D45, EXP_D45, EXP_D45, EXP_D25, EXP_REUSE }, { EXP_D45, EXP_D45, EXP_D45, EXP_D45, EXP_D45, EXP_D45 } }; aften/libaften/a52tab.h000066400000000000000000000032561132016273200151710ustar00rootroot00000000000000/** * Aften: A/52 audio encoder - A/52 tables * Copyright (c) 2008 Prakash Punnoor * * Based on "The simplest AC3 encoder" from FFmpeg * Copyright (c) 2000 Fabrice Bellard. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef A52TAB_H #define A52TAB_H #include "common.h" extern const uint16_t a52_frame_size_tab[38][3]; extern const uint8_t a52_channels_tab[8]; extern const uint16_t a52_sample_rate_tab[3]; extern const uint16_t a52_bitrate_tab[19]; extern const uint8_t a52_log_add_tab[260]; extern const uint16_t a52_hearing_threshold_tab[50][3]; extern const uint8_t a52_bap_tab[64]; extern const uint8_t a52_slow_decay_tab[4]; extern const uint8_t a52_fast_decay_tab[4]; extern const uint16_t a52_slow_gain_tab[4]; extern const uint16_t a52_db_per_bit_tab[4]; extern const int16_t a52_floor_tab[8]; extern const uint16_t a52_fast_gain_tab[8]; extern const uint8_t a52_critical_band_size_tab[50]; extern const uint8_t a52_expstr_set_tab[32][6]; #endif /* A52TAB_H */ aften/libaften/aften-types.h000066400000000000000000000225161132016273200163520ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * Copyright (c) 2006-2007 Justin Ruggles * 2006-2007 Prakash Punnoor * * Based on "The simplest AC3 encoder" from FFmpeg * Copyright (c) 2000 Fabrice Bellard. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file aften-types.h * libaften public header for type definitions */ #ifndef AFTEN_TYPES_H #define AFTEN_TYPES_H #ifdef __cplusplus extern "C" { #endif /** * Some helpful size constants */ enum { A52_MAX_CODED_FRAME_SIZE = 3840, A52_SAMPLES_PER_FRAME = 1536 }; /** * Aften's mode of operation */ typedef enum { AFTEN_ENCODE, AFTEN_TRANSCODE } AftenOperationMode; /** * Aften Encoding Mode */ typedef enum { AFTEN_ENC_MODE_CBR = 0, AFTEN_ENC_MODE_VBR } AftenEncMode; /** * Floating-Point Data Types */ typedef enum { FLOAT_TYPE_DOUBLE, FLOAT_TYPE_FLOAT } FloatType; /** * Audio Sample Formats */ typedef enum { A52_SAMPLE_FMT_U8 = 0, A52_SAMPLE_FMT_S16, A52_SAMPLE_FMT_S20, A52_SAMPLE_FMT_S24, A52_SAMPLE_FMT_S32, A52_SAMPLE_FMT_FLT, A52_SAMPLE_FMT_DBL, A52_SAMPLE_FMT_S8 } A52SampleFormat; /** * Dynamic Range Profiles */ typedef enum { DYNRNG_PROFILE_FILM_LIGHT=0, DYNRNG_PROFILE_FILM_STANDARD, DYNRNG_PROFILE_MUSIC_LIGHT, DYNRNG_PROFILE_MUSIC_STANDARD, DYNRNG_PROFILE_SPEECH, DYNRNG_PROFILE_NONE } DynRngProfile; /** * Audio Coding Mode (acmod) options */ enum { A52_ACMOD_DUAL_MONO = 0, A52_ACMOD_MONO, A52_ACMOD_STEREO, A52_ACMOD_3_0, A52_ACMOD_2_1, A52_ACMOD_3_1, A52_ACMOD_2_2, A52_ACMOD_3_2 }; /** * SIMD instruction sets */ typedef struct { int mmx; int sse; int sse2; int sse3; int ssse3; int amd_3dnow; int amd_3dnowext; int amd_sse_mmx; int altivec; } AftenSimdInstructions; /** * Performance related parameters */ typedef struct { /** * Number of threads * How many threads should be used. * Default value is 0, which indicates detecting number of CPUs. * Maximum value is AFTEN_MAX_THREADS. */ int n_threads; /** * Available SIMD instruction sets; shouldn't be modified */ AftenSimdInstructions available_simd_instructions; /** * Wanted SIMD instruction sets */ AftenSimdInstructions wanted_simd_instructions; } AftenSystemParams; /** * Parameters which affect encoded audio output */ typedef struct { /** * Bitrate selection mode. * AFTEN_ENC_MODE_CBR : constant bitrate * AFTEN_ENC_MODE_VBR : variable bitrate * default is CBR */ AftenEncMode encoding_mode; /** * Stereo rematrixing option. * Set to 0 to disable stereo rematrixing, 1 to enable it. * default is 1 */ int use_rematrixing; /** * Block switching option. * Set to 0 to disable block switching, 1 to enable it. * default is 0 */ int use_block_switching; /** * DC high-pass filter option. * Set to 0 to disable the filter, 1 to enable it. * default is 0 */ int use_dc_filter; /** * Bandwidth low-pass filter option. * Set to 0 to disable the, 1 to enable it. * default is 0 */ int use_bw_filter; /** * LFE low-pass filter option. * Set to 0 to disable the filter, 1 to enable it. * This limits the LFE bandwidth, and can only be used if the input audio * has an LFE channel. * default is 0 */ int use_lfe_filter; /** * Constant bitrate. * This option sets the bitrate for CBR encoding mode. * It can also be used to set the maximum bitrate for VBR mode. * It is specified in kbps. Only certain bitrates are valid: * 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, * 160, 192, 224, 256, 320, 384, 448, 512, 576, 640 * default is 0 * For CBR mode, this selects bitrate based on the number of channels. * For VBR mode, this sets the maximum bitrate to 640 kbps. */ int bitrate; /** * VBR Quality. * This option sets the target quality for VBR encoding mode. * The range is 0 to 1023 and corresponds to the SNR offset. * default is 240 */ int quality; /** * Bandwidth code. * This option determines the cutoff frequency for encoded bandwidth. * 0 to 60 corresponds to a cutoff of 28.5% to 98.8% of the full bandwidth. * -1 is used for constant adaptive bandwidth. Aften selects a good value * based on the quality or bitrate parameters. * -2 is used for variable adaptive bandwidth. Aften selects a value for * each frame based on the encoding quality level for that frame. * default is -1 */ int bwcode; /** * Bit Allocation speed/accuracy * This determines how accurate the bit allocation search method is. * Set to 0 for better quality * Set to 1 for faster encoding * default is 0 */ int bitalloc_fast; /** * Exponent Strategy search size * This determines how many exponent strategy sets to search through to * find the best combination. * minimum is 1 (fixed strategy, lower quality, faster encoding) * maximum is 32 (higher quality, slower encoding) * default is 8 */ int expstr_search; /** * Dynamic Range Compression profile * This determines which DRC profile to use. * Film Light: DYNRNG_PROFILE_FILM_LIGHT * Film Standard: DYNRNG_PROFILE_FILM_STANDARD * Music Light: DYNRNG_PROFILE_MUSIC_LIGHT * Music Standard: DYNRNG_PROFILE_MUSIC_STANDARD * Speech: DYNRNG_PROFILE_SPEECH, * None: DYNRNG_PROFILE_NONE * default is None */ DynRngProfile dynrng_profile; /** * Minimum bandwidth code. * For use with variable bandwidth mode, this option determines the * minimum value for the bandwidth code. * default is 0. */ int min_bwcode; /** * Maximum bandwidth code. * For use with variable bandwidth mode, this option determines the * maximum value for the bandwidth code. * default is 60. */ int max_bwcode; } AftenEncParams; /** * Metadata parameters * See the A/52 specification for details regarding the metadata. */ typedef struct { /** Center mix level */ int cmixlev; /** Surround mix level */ int surmixlev; /** Dolby(R) Surround mode */ int dsurmod; /** Dialog normalization */ int dialnorm; /** Extended bit stream info 1 exists */ int xbsi1e; /** Preferred downmix mode */ int dmixmod; /** LtRt center mix level */ int ltrtcmixlev; /** LtRt surround mix level */ int ltrtsmixlev; /** LoRo center mix level */ int lorocmixlev; /** LoRo surround mix level */ int lorosmixlev; /** Extended bit stream info 2 exists */ int xbsi2e; /** Dolby(R) Surround EX mode */ int dsurexmod; /** Dolby(R) Headphone mode */ int dheadphonmod; /** A/D converter type */ int adconvtyp; } AftenMetadata; /** * Values in this structure are updated by Aften during encoding. * They give information about the previously encoded frame. */ typedef struct { int quality; int bit_rate; int bwcode; } AftenStatus; /** * libaften public encoding context */ typedef struct { AftenEncParams params; AftenMetadata meta; AftenStatus status; AftenSystemParams system; AftenOperationMode mode; /** * Verbosity level. * 0 is quiet mode. 1 and 2 are more verbose. * default is 1 */ int verbose; /** * Total number of channels in the input stream. */ int channels; /** * Audio coding mode (channel configuration). * There are utility functions to set this if you don't know the proper * value. */ int acmod; /** * Indicates that there is an LFE channel present. * There are utility functions to set this if you don't know the proper * value. */ int lfe; /** * Audio sample rate in Hz */ int samplerate; /** * Audio sample format * default: A52_SAMPLE_FMT_S16 */ A52SampleFormat sample_format; /** * Initial samples * To prevent padding und thus to get perfect sync, * exactly 256 samples/channel can be provided here. * This is not recommended, as without padding these samples can't be properly * reconstructed anymore. */ void* initial_samples; /** * Used internally by the encoder. The user should leave this alone. * It is allocated in aften_encode_init and free'd in aften_encode_close. */ void *private_context; } AftenContext; #if defined(__cplusplus) } #endif #endif /* AFTEN_TYPES_H */ aften/libaften/aften.h000066400000000000000000000121311132016273200152000ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * Copyright (c) 2006-2007 Justin Ruggles * 2006-2007 Prakash Punnoor * * Based on "The simplest AC3 encoder" from FFmpeg * Copyright (c) 2000 Fabrice Bellard. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file aften.h * libaften public header for function declarations */ #ifndef AFTEN_H #define AFTEN_H #ifdef __cplusplus extern "C" { #endif #include "aften-types.h" #if defined(_WIN32) && !defined(_XBOX) #if defined(AFTEN_BUILD_LIBRARY) #define AFTEN_API __declspec(dllexport) #else #define AFTEN_API __declspec(dllimport) #endif #else #if defined(AFTEN_BUILD_LIBRARY) && defined(HAVE_GCC_VISIBILITY) #define AFTEN_API __attribute__((visibility("default"))) #else #define AFTEN_API extern #endif #endif /** * @defgroup encoding Main encoding functions * @{ */ /** * Gets the libaften version string. */ AFTEN_API const char *aften_get_version(void); /** * Sets the parameters for an encoding context to their default values. * @param s The encoding context */ AFTEN_API void aften_set_defaults(AftenContext *s); /** * Initializes an encoding context. * This must be called before any calls to @c aften_encode_frame * @param s The encoding context * @return Returns 0 on success, non-zero on failure. */ AFTEN_API int aften_encode_init(AftenContext *s); /** * Encodes a single AC-3 frame. * @param s The encoding context * @param[out] frame_buffer Pointer to output frame data * @param[in] samples Pointer to input audio samples * @param[in] count Number of input audio samples (per channel); * must be equal to A52_SAMPLES_PER_FRAME, less than A52_SAMPLES_PER_FRAME * for the last frame, and equal to 0 while flushing * @return Returns the number of bytes written to @p frame_buffer, or returns * a negative value on error. */ AFTEN_API int aften_encode_frame(AftenContext *s, unsigned char *frame_buffer, const void *samples, int count); /** * Sets the parameters in the context @p s to their default values. * @param s The encoding context * @return Returns a negative value on error. */ AFTEN_API int aften_encode_close(AftenContext *s); /** @} end encoding functions */ /** * @defgroup utility Utility functions * @{ */ /** * Determines the proper A/52 acmod and lfe parameters based on the * number of channels and the WAVE_FORMAT_EXTENSIBLE channel mask. If the * chmask value has the high bit set to 1 (e.g. 0xFFFFFFFF), then the default * plain WAVE channel selection is assumed. * @param[in] ch number of channels * @param[in] chmask channel mask * @param[out] acmod pointer to audio coding mode * @param[out] lfe pointer to LFE flag * @return On error, the @p acmod and @p lfe output params are set to -1 and * the function returns -1; on success, the @p acmod and @p lfe params are set * to appropriate values and the function returns 0. */ AFTEN_API int aften_wav_channels_to_acmod(int ch, unsigned int chmask, int *acmod, int *lfe); /** * Takes a channel-interleaved array of audio samples, where the channel order * is the default WAV order. The samples are rearranged to the proper A/52 * channel order based on the @p acmod and @p lfe parameters. * @param samples array of interleaved audio samples * @param[in] n number of samples in the array * @param[in] ch number of channels * @param[in] fmt sample format * @param[in] acmod audio coding mode */ AFTEN_API void aften_remap_wav_to_a52(void *samples, int n, int ch, A52SampleFormat fmt, int acmod); /** * Takes a channel-interleaved array of audio samples, where the channels are * in MPEG order. The samples are rearranged to the proper A/52 channel order * based on the @p acmod parameter. * @param samples array of interleaved audio samples * @param[in] n number of samples in the array * @param[in] ch number of channels * @param[in] fmt sample format * @param[in] acmod audio coding mode */ AFTEN_API void aften_remap_mpeg_to_a52(void *samples, int n, int ch, A52SampleFormat fmt, int acmod); /** * Tells whether libaften was configured to use floats or doubles */ AFTEN_API FloatType aften_get_float_type(void); /** @} end utility functions */ #undef AFTEN_API #if defined(__cplusplus) } #endif #endif /* AFTEN_H */ aften/libaften/bitalloc.c000066400000000000000000000403301132016273200156710ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * Copyright (c) 2006 Justin Ruggles * Prakash Punnoor * * Based on "The simplest AC3 encoder" from FFmpeg * Copyright (c) 2000 Fabrice Bellard. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file bitalloc.c * A/52 bit allocation */ #include "a52enc.h" #include "bitalloc.h" /** * A52 bit allocation preparation to speed up matching left bits. * This generates the power-spectral densities and the masking curve based on * the mdct coefficient exponents and bit allocation parameters. */ static void a52_bit_allocation_prepare(A52BitAllocParams *s, uint8_t *exp, int16_t *psd, int16_t *mask, int fgain, int start, int end) // int deltbae,int deltnseg, uint8_t *deltoffst, // uint8_t *deltlen, uint8_t *deltba) { int16_t bndpsd[50]; // power spectral density for critical bands a52_bit_alloc_calc_psd(exp, start, end, psd, bndpsd); a52_bit_alloc_calc_mask(s, bndpsd, start, end, fgain, -1, -1, NULL, NULL, NULL,/* delta bit allocation not used */ mask); } /** * Calculate the size in bits taken by the mantissas. * This is determined solely by the bit allocation pointers. */ static int compute_mantissa_size(int mant_cnt[5], uint8_t *bap, int ncoefs) { int bits, b, i; bits = 0; for (i = 0; i < ncoefs; i++) { b = bap[i]; if (b <= 4) { // bap=1 to bap=4 will be counted in compute_mantissa_size_final ++mant_cnt[b]; } else if (b <= 13) { // bap=5 to bap=13 use (bap-1) bits bits += b-1; } else { // bap=14 uses 14 bits and bap=15 uses 16 bits bits += 14 + ((b-14)<<1); } } return bits; } /** Finalize the mantissa bit count by adding in the grouped mantissas */ static int compute_mantissa_size_final(int mant_cnt[5]) { // bap=1 : 3 mantissas in 5 bits int bits = (mant_cnt[1] / 3) * 5; // bap=2 : 3 mantissas in 7 bits // bap=4 : 2 mantissas in 7 bits bits += ((mant_cnt[2] / 3) + (mant_cnt[4] >> 1)) * 7; // bap=3 : each mantissa is 3 bits bits += mant_cnt[3] * 3; return bits; } /* call to prepare bit allocation */ static void bit_alloc_prepare(A52ThreadContext *tctx) { A52Context *ctx = tctx->ctx; A52Frame *frame = &tctx->frame; A52Block *block; int blk, ch; for (blk = 0; blk < A52_NUM_BLOCKS; blk++) { block = &frame->blocks[blk]; for (ch = 0; ch < ctx->n_all_channels; ch++) { // We don't have to run the bit allocation when reusing exponents if (block->exp_strategy[ch] != EXP_REUSE) { a52_bit_allocation_prepare(&frame->bit_alloc, block->exp[ch], block->psd[ch], block->mask[ch], frame->bit_alloc.fgain[blk][ch], 0, frame->ncoefs[ch]); // 2, 0, NULL, NULL, NULL); } } } } /** * Run the bit allocation routine using the given snroffset values. * Returns number of mantissa bits used. */ static int bit_alloc(A52ThreadContext *tctx, int snroffst) { A52Context *ctx = tctx->ctx; A52Frame *frame = &tctx->frame; A52Block *block; int mant_cnt[5]; int blk, ch; int bits; bits = 0; snroffst = (snroffst << 2) - 960; for (blk = 0; blk < A52_NUM_BLOCKS; blk++) { block = &frame->blocks[blk]; // initialize grouped mantissa counts. these are set so that they are // padded to the next whole group size when bits are counted in // compute_mantissa_size_final mant_cnt[0] = mant_cnt[3] = 0; mant_cnt[1] = mant_cnt[2] = 2; mant_cnt[4] = 1; for (ch = 0; ch < ctx->n_all_channels; ch++) { // Currently the encoder is setup so that the only bit allocation // parameter which varies across blocks within a frame is the // exponent values. We can take advantage of that by reusing the // bit allocation pointers whenever we reuse exponents. if (block->exp_strategy[ch] == EXP_REUSE) { memcpy(block->bap[ch], frame->blocks[blk-1].bap[ch], 256); } else { a52_bit_alloc_calc_bap(block->mask[ch], block->psd[ch], 0, frame->ncoefs[ch], snroffst, frame->bit_alloc.floor, block->bap[ch]); } bits += compute_mantissa_size(mant_cnt, block->bap[ch], frame->ncoefs[ch]); } bits += compute_mantissa_size_final(mant_cnt); } return bits; } /** Counts all frame bits except for mantissas and exponents */ static void count_frame_bits(A52ThreadContext *tctx) { static int frame_bits_inc[8] = { 8, 0, 2, 2, 2, 4, 2, 4 }; A52Context *ctx = tctx->ctx; A52Frame *frame = &tctx->frame; A52Block *block; int blk, ch; int frame_bits; frame_bits = 0; // header size frame_bits += 65; frame_bits += frame_bits_inc[ctx->acmod]; if (ctx->meta.xbsi1e) frame_bits += 14; if (ctx->meta.xbsi2e) frame_bits += 14; // audio blocks for (blk = 0; blk < A52_NUM_BLOCKS; blk++) { block = &frame->blocks[blk]; frame_bits += ctx->n_channels; // blksw frame_bits += ctx->n_channels; // dithflg frame_bits += 1 + (ctx->acmod == A52_ACMOD_DUAL_MONO); // dynrnge, dynrng2e if (ctx->params.dynrng_profile != DYNRNG_PROFILE_NONE) { frame_bits += 8; // dynrng if (ctx->acmod == A52_ACMOD_DUAL_MONO) frame_bits += 8; // dynrng2 } frame_bits++; // cplstre if (!blk) { frame_bits++; // cplinu } if (ctx->acmod == 2) { frame_bits++; // rematstr if (!blk) frame_bits += 4; // rematflg } frame_bits += 2 * ctx->n_channels; // chexpstr if (ctx->lfe) frame_bits++; // lfeexpstr for (ch = 0; ch < ctx->n_channels; ch++) { if (block->exp_strategy[ch] != EXP_REUSE) { frame_bits += 6; // chbwcod frame_bits += 2; // gainrng } } frame_bits++; // baie if (!blk) { // sdcycod[2], fdcycod[2], sgaincod[2], dbpbcod[2], floorcod[3] frame_bits += 2 + 2 + 2 + 2 + 3; } frame_bits++; // snr if (block->write_snr) { frame_bits += 6; // csnroffset frame_bits += ctx->n_all_channels * 4; // fsnroffset frame_bits += ctx->n_all_channels * 3; // fgaincod } frame_bits++; // delta frame_bits++; // skip } // auxdatae, crcrsv frame_bits += 2; // CRC frame_bits += 16; frame->frame_bits = frame_bits; } /** * Calculates the snroffset values which, when used, keep the size of the * encoded data within a fixed frame size. */ static int cbr_bit_allocation(A52ThreadContext *tctx, int prepare) { A52Context *ctx = tctx->ctx; A52Frame *frame = &tctx->frame; int current_bits, avail_bits, leftover; int snroffst=0; current_bits = frame->frame_bits + frame->exp_bits; avail_bits = (16 * frame->frame_size) - current_bits; if (prepare) bit_alloc_prepare(tctx); // starting point if (ctx->params.encoding_mode == AFTEN_ENC_MODE_VBR) snroffst = ctx->params.quality; else if (ctx->params.encoding_mode == AFTEN_ENC_MODE_CBR) snroffst = tctx->last_quality; leftover = avail_bits - bit_alloc(tctx, snroffst); if (ctx->params.bitalloc_fast) { // fast bit allocation int leftover0, leftover1, snr0, snr1; snr0 = snr1 = snroffst; leftover0 = leftover1 = leftover; if (leftover != 0) { if (leftover > 0) { while (leftover1 > 0 && snr1+16 <= 1023) { snr0 = snr1; leftover0 = leftover1; snr1 += 16; leftover1 = avail_bits - bit_alloc(tctx, snr1); } } else { while (leftover0 < 0 && snr0-16 >= 0) { snr1 = snr0; leftover1 = leftover0; snr0 -= 16; leftover0 = avail_bits - bit_alloc(tctx, snr0); } } } if (snr0 != snr1) { snroffst = snr0; leftover = avail_bits - bit_alloc(tctx, snroffst); } } else { // take up to 3 jumps based on estimated distance from optimal if (leftover < -400) { snroffst += (leftover / (16 * ctx->n_channels)); leftover = avail_bits - bit_alloc(tctx, snroffst); } if (leftover > 400) { snroffst += (leftover / (24 * ctx->n_channels)); leftover = avail_bits - bit_alloc(tctx, snroffst); } if (leftover < -200) { snroffst += (leftover / (40 * ctx->n_channels)); leftover = avail_bits - bit_alloc(tctx, snroffst); } // adjust snroffst until leftover <= -100 while (leftover > -100) { snroffst += (10 / ctx->n_channels); if (snroffst > 1023) { snroffst = 1023; leftover = avail_bits - bit_alloc(tctx, snroffst); break; } leftover = avail_bits - bit_alloc(tctx, snroffst); } // adjust snroffst until leftover is positive while (leftover < 0 && snroffst > 0) { snroffst--; leftover = avail_bits - bit_alloc(tctx, snroffst); } } frame->mant_bits = avail_bits - leftover; if (leftover < 0) { fprintf(stderr, "bitrate: %d kbps too small\n", frame->bit_rate); return -1; } // set encoding parameters frame->csnroffst = snroffst >> 4; frame->fsnroffst = snroffst & 0xF; frame->quality = snroffst; tctx->last_quality = snroffst; return 0; } /** * Finds the frame size which will hold all of the data when using an * snroffset value as determined by the user-selected quality setting. */ static int vbr_bit_allocation(A52ThreadContext *tctx) { A52Context *ctx = tctx->ctx; A52Frame *frame = &tctx->frame; int i; int frame_size; int quality; int frame_bits, current_bits; current_bits = frame->frame_bits + frame->exp_bits; quality = ctx->params.quality; bit_alloc_prepare(tctx); // find an A52 frame size that can hold the data. frame_size = 0; frame_bits = current_bits + bit_alloc(tctx, quality); for (i = 0; i <= ctx->frmsizecod; i++) { frame_size = a52_frame_size_tab[i][ctx->fscod]; if (frame_size >= frame_bits) break; } i = MIN(i, ctx->frmsizecod); frame->bit_rate = a52_bitrate_tab[i/2] >> ctx->halfratecod; frame->frmsizecod = i; frame->frame_size = frame_size / 16; frame->frame_size_min = frame->frame_size; // run CBR bit allocation. // this will increase snroffst to make optimal use of the frame bits. // also it will lower snroffst if vbr frame won't fit in largest frame. return cbr_bit_allocation(tctx, 0); } /** * Loads the bit allocation parameters and counts fixed frame bits. */ static void start_bit_allocation(A52ThreadContext *tctx) { A52Context *ctx = tctx->ctx; A52Frame *frame = &tctx->frame; A52Block *block; int blk, ch; // read bit allocation table values frame->bit_alloc.fscod = ctx->fscod; frame->bit_alloc.halfratecod = ctx->halfratecod; frame->bit_alloc.sdecay = a52_slow_decay_tab[frame->sdecaycod] >> ctx->halfratecod; frame->bit_alloc.fdecay = a52_fast_decay_tab[frame->fdecaycod] >> ctx->halfratecod; frame->bit_alloc.sgain = a52_slow_gain_tab[frame->sgaincod]; frame->bit_alloc.dbknee = a52_db_per_bit_tab[frame->dbkneecod]; frame->bit_alloc.floor = a52_floor_tab[frame->floorcod]; // set fast gain based on exponent strategy for (blk = 0; blk < A52_NUM_BLOCKS; blk++) { block = &frame->blocks[blk]; block->write_snr = 0; for (ch = 0; ch < ctx->n_all_channels; ch++) { if (block->exp_strategy[ch] != EXP_REUSE) { block->fgaincod[ch] = 4 - block->exp_strategy[ch]; block->write_snr |= !blk || (block->fgaincod[ch] != frame->blocks[blk-1].fgaincod[ch]); } else { block->fgaincod[ch] = frame->blocks[blk-1].fgaincod[ch]; } frame->bit_alloc.fgain[blk][ch] = a52_fast_gain_tab[block->fgaincod[ch]]; } } count_frame_bits(tctx); } /** estimated number of bits used for a mantissa, indexed by bap value. */ static FLOAT mant_est_tab[16] = { FCONST( 0.000), FCONST( 1.667), FCONST( 2.333), FCONST( 3.000), FCONST( 3.500), FCONST( 4.000), FCONST( 5.000), FCONST( 6.000), FCONST( 7.000), FCONST( 8.000), FCONST( 9.000), FCONST(10.000), FCONST(11.000), FCONST(12.000), FCONST(14.000), FCONST(16.000) }; /** * Variable bandwidth bit allocation * This estimates the bandwidth code which will give quality around 240. */ void vbw_bit_allocation(A52ThreadContext *tctx) { A52Context *ctx = tctx->ctx; A52Frame *frame = &tctx->frame; FLOAT mant_bits; int blk, ch, bw, nc; int avail_bits, bits; int wmin, wmax, ncmin, ncmax; start_bit_allocation(tctx); avail_bits = (16 * frame->frame_size) - frame->frame_bits; bit_alloc_prepare(tctx); bit_alloc(tctx, 240); // deduct any LFE exponent and mantissa bits if (ctx->lfe) { FLOAT lfe_bits = FCONST(0.0); ch = ctx->lfe_channel; lfe_bits += expstr_set_bits[frame->expstr_set[ch]][7]; for (blk = 0; blk < A52_NUM_BLOCKS; blk++) { uint8_t *bap = frame->blocks[blk].bap[ch]; for (nc = 0; nc < 7; nc++) lfe_bits += mant_est_tab[bap[nc]]; } avail_bits -= (int)lfe_bits; } // set limits wmin = ctx->params.min_bwcode; wmax = ctx->params.max_bwcode; ncmin = wmin * 3 + 73; ncmax = wmax * 3 + 73; // sum up mantissa bits up to bin 72 mant_bits = FCONST(0.0); for (ch = 0; ch < ctx->n_channels; ch++) { for (blk = 0; blk < A52_NUM_BLOCKS; blk++) { uint8_t *bap = frame->blocks[blk].bap[ch]; for (nc = 0; nc < ncmin; nc++) mant_bits += mant_est_tab[bap[nc]]; } } // add bins while estimated bits fit in the frame for (nc = ncmin; nc <= ncmax; nc++) { bw = (nc - 73) / 3; bits = 0; for (ch = 0; ch < ctx->n_channels; ch++) { bits += expstr_set_bits[frame->expstr_set[ch]][nc]; for (blk = 0; blk < A52_NUM_BLOCKS; blk++) mant_bits += mant_est_tab[frame->blocks[blk].bap[ch][nc]]; } if ((bits + (int)mant_bits) > avail_bits) break; } // set frame bandwidth parameters bw = CLIP((nc - 73) / 3, 0, 60); nc = bw * 3 + 73; frame->bwcode = bw; for (ch = 0; ch < ctx->n_channels; ch++) frame->ncoefs[ch] = nc; } /** * Run the bit allocation encoding routine. * Runs the bit allocation in either CBR or VBR mode, depending on the mode * selected by the user. */ int compute_bit_allocation(A52ThreadContext *tctx) { A52Context *ctx = tctx->ctx; start_bit_allocation(tctx); if (ctx->params.encoding_mode == AFTEN_ENC_MODE_VBR) { if (vbr_bit_allocation(tctx)) return -1; } else if(ctx->params.encoding_mode == AFTEN_ENC_MODE_CBR) { if (cbr_bit_allocation(tctx, 1)) return -1; } else { return -1; } return 0; } aften/libaften/bitalloc.h000066400000000000000000000022431132016273200156770ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * Copyright (c) 2006 Justin Ruggles * * Based on "The simplest AC3 encoder" from FFmpeg * Copyright (c) 2000 Fabrice Bellard. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file bitalloc.h * A/52 bit allocation header */ #ifndef BITALLOC_H #define BITALLOC_H struct A52ThreadContext; extern void vbw_bit_allocation(struct A52ThreadContext *tctx); extern int compute_bit_allocation(struct A52ThreadContext *tctx); #endif /* BITALLOC_H */ aften/libaften/bitio.c000066400000000000000000000054761132016273200152220ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * Copyright (c) 2006 Justin Ruggles * * Based on "The simplest AC3 encoder" from FFmpeg * Copyright (c) 2000 Fabrice Bellard. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file bitio.c * Bitwise file writer */ #include "bitio.h" void bitwriter_init(BitWriter *bw, void *buf, int len) { if (len < 0) { len = 0; buf = NULL; } bw->buffer = buf; bw->buf_end = bw->buffer + len; bw->buf_ptr = bw->buffer; bw->bit_left = 32; bw->bit_buf = 0; bw->eof = 0; } void bitwriter_flushbits(BitWriter *bw) { bw->bit_buf <<= bw->bit_left; while (bw->bit_left < 32) { *bw->buf_ptr++ = bw->bit_buf >> 24; bw->bit_buf <<= 8; bw->bit_left += 8; } bw->bit_left = 32; bw->bit_buf = 0; } void bitwriter_writebits(BitWriter *bw, int bits, uint32_t val) { if (!bits || bits > 32) return; val = (val & ((1U << bits)-1)); if (bits <= bw->bit_left) { bw->bit_buf = (bw->bit_buf << bits) | val; bw->bit_left -= bits; } else { uint32_t bb = (bw->bit_buf << bw->bit_left) | (val >> (bits - bw->bit_left)); if (bw->buffer != NULL) { if (bw->eof) return; if ((bw->buf_ptr+3) >= bw->buf_end) { bw->eof = 1; return; } *(uint32_t *)bw->buf_ptr = be2me_32(bb); } bw->bit_left += (32 - bits); bw->buf_ptr += 4; bw->bit_buf = val; } } void bitwriter_writebit(BitWriter *bw, uint8_t val) { if (bw->bit_left) { bw->bit_buf = (bw->bit_buf << 1) | (val & 1); bw->bit_left--; } else { if (bw->buffer != NULL) { if (bw->eof) return; if ((bw->buf_ptr+3) >= bw->buf_end) { bw->eof = 1; return; } *(uint32_t *)bw->buf_ptr = be2me_32(bw->bit_buf); } bw->bit_left = 31; bw->buf_ptr += 4; bw->bit_buf = (val & 1); } } uint32_t bitwriter_bitcount(BitWriter *bw) { return (((bw->buf_ptr - bw->buffer) << 3) + 32 - bw->bit_left); } aften/libaften/bitio.h000066400000000000000000000027011132016273200152130ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * Copyright (c) 2006 Justin Ruggles * * Based on "The simplest AC3 encoder" from FFmpeg * Copyright (c) 2000 Fabrice Bellard. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file bitio.h * Bitwise file writer header */ #ifndef BITIO_H #define BITIO_H #include "common.h" typedef struct BitWriter { uint32_t bit_buf; int bit_left; uint8_t *buffer, *buf_ptr, *buf_end; int eof; } BitWriter; extern void bitwriter_init(BitWriter *bw, void *buf, int len); extern void bitwriter_flushbits(BitWriter *bw); extern void bitwriter_writebits(BitWriter *bw, int bits, uint32_t val); extern void bitwriter_writebit(BitWriter *bw, uint8_t val); extern uint32_t bitwriter_bitcount(BitWriter *bw); #endif /* BITIO_H */ aften/libaften/convert.c000066400000000000000000000124121132016273200155600ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * Copyright (c) 2006 Justin Ruggles * 2007 Prakash Punnoor * * Based on "The simplest AC3 encoder" from FFmpeg * Copyright (c) 2000 Fabrice Bellard. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file convert.c * converts external format to internal format */ #include "a52enc.h" #include "convert.h" static void fmt_convert_from_u8(FLOAT dest[A52_MAX_CHANNELS][A52_SAMPLES_PER_FRAME], const void *vsrc, int nch, int n) { int i, j, ch; const uint8_t *src = vsrc; for (ch = 0; ch < nch; ch++) { FLOAT *dest_ch = dest[ch]; const uint8_t *src_ch = src + ch; for (i = 0, j = 0; i < n; i++, j += nch) { dest_ch[i] = (src_ch[j]-FCONST(128.0)) / FCONST(128.0); } } } static void fmt_convert_from_s8(FLOAT dest[A52_MAX_CHANNELS][A52_SAMPLES_PER_FRAME], const void *vsrc, int nch, int n) { int i, j, ch; const int8_t *src = vsrc; for (ch = 0; ch < nch; ch++) { FLOAT *dest_ch = dest[ch]; const int8_t *src_ch = src + ch; for (i = 0, j = 0; i < n; i++, j += nch) { dest_ch[i] = src_ch[j] / FCONST(128.0); } } } static void fmt_convert_from_s16(FLOAT dest[A52_MAX_CHANNELS][A52_SAMPLES_PER_FRAME], const void *vsrc, int nch, int n) { int i, j, ch; const int16_t *src = vsrc; for (ch = 0; ch < nch; ch++) { FLOAT *dest_ch = dest[ch]; const int16_t *src_ch = src + ch; for (i = 0, j = 0; i < n; i++, j += nch) { dest_ch[i] = src_ch[j] / FCONST(32768.0); } } } static void fmt_convert_from_s20(FLOAT dest[A52_MAX_CHANNELS][A52_SAMPLES_PER_FRAME], const void *vsrc, int nch, int n) { int i, j, ch; const int32_t *src = vsrc; for (ch = 0; ch < nch; ch++) { FLOAT *dest_ch = dest[ch]; const int32_t *src_ch = src + ch; for (i = 0, j = 0; i < n; i++, j += nch) { dest_ch[i] = src_ch[j] / FCONST(524288.0); } } } static void fmt_convert_from_s24(FLOAT dest[A52_MAX_CHANNELS][A52_SAMPLES_PER_FRAME], const void *vsrc, int nch, int n) { int i, j, ch; const int32_t *src = vsrc; for (ch = 0; ch < nch; ch++) { FLOAT *dest_ch = dest[ch]; const int32_t *src_ch = src + ch; for (i = 0, j = 0; i < n; i++, j += nch) { dest_ch[i] = src_ch[j] / FCONST(8388608.0); } } } static void fmt_convert_from_s32(FLOAT dest[A52_MAX_CHANNELS][A52_SAMPLES_PER_FRAME], const void *vsrc, int nch, int n) { int i, j, ch; const int32_t *src = vsrc; for (ch = 0; ch < nch; ch++) { FLOAT *dest_ch = dest[ch]; const int32_t *src_ch = src + ch; for (i = 0, j = 0; i < n; i++, j += nch) { dest_ch[i] = src_ch[j] / FCONST(2147483648.0); } } } static void fmt_convert_from_float(FLOAT dest[A52_MAX_CHANNELS][A52_SAMPLES_PER_FRAME], const void *vsrc, int nch, int n) { int i, j, ch; const float *src = vsrc; for (ch = 0; ch < nch; ch++) { FLOAT *dest_ch = dest[ch]; const float *src_ch = src + ch; for (i = 0, j = 0; i < n; i++, j += nch) { dest_ch[i] = src_ch[j]; } } } static void fmt_convert_from_double(FLOAT dest[A52_MAX_CHANNELS][A52_SAMPLES_PER_FRAME], const void *vsrc, int nch, int n) { int i, j, ch; const double *src = vsrc; for (ch = 0; ch < nch; ch++) { FLOAT *dest_ch = dest[ch]; const double *src_ch = src + ch; for (i = 0, j = 0; i < n; i++, j += nch) { dest_ch[i] = (FLOAT)src_ch[j]; } } } void set_converter(A52Context *ctx, A52SampleFormat sample_format) { switch (sample_format) { case A52_SAMPLE_FMT_U8: ctx->fmt_convert_from_src = fmt_convert_from_u8; break; case A52_SAMPLE_FMT_S8: ctx->fmt_convert_from_src = fmt_convert_from_s8; break; case A52_SAMPLE_FMT_S16: ctx->fmt_convert_from_src = fmt_convert_from_s16; break; case A52_SAMPLE_FMT_S20: ctx->fmt_convert_from_src = fmt_convert_from_s20; break; case A52_SAMPLE_FMT_S24: ctx->fmt_convert_from_src = fmt_convert_from_s24; break; case A52_SAMPLE_FMT_S32: ctx->fmt_convert_from_src = fmt_convert_from_s32; break; case A52_SAMPLE_FMT_FLT: ctx->fmt_convert_from_src = fmt_convert_from_float; break; case A52_SAMPLE_FMT_DBL: ctx->fmt_convert_from_src = fmt_convert_from_double; break; default: break; } } aften/libaften/convert.h000066400000000000000000000022071132016273200155660ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * Copyright (c) 2006 Justin Ruggles * 2007 Prakash Punnoor * * Based on "The simplest AC3 encoder" from FFmpeg * Copyright (c) 2000 Fabrice Bellard. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file convert.h * converts external format to internal format; header */ #include "common.h" struct A52Context; void set_converter(A52Context *ctx, A52SampleFormat sample_format); aften/libaften/cpu_caps.h000066400000000000000000000032201132016273200156770ustar00rootroot00000000000000/********************************************************************* * Copyright (C) 2006 by Prakash Punnoor * * prakash@punnoor.de * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Library General Public * * License as published by the Free Software Foundation; * * version 2 of the License * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Library General Public License for more details. * * * * You should have received a copy of the GNU Library General Public * * License along with this library; if not, write to the * * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * * Boston, MA 02110-1301, USA. * *********************************************************************/ #ifndef CPU_CAPS_H #define CPU_CAPS_H #if defined(HAVE_MMX) || defined(HAVE_SSE) #include "x86/cpu_caps.h" #elif defined(HAVE_ALTIVEC) #include "ppc/cpu_caps.h" #else static inline void cpu_caps_detect(void){} static inline void apply_simd_restrictions(AftenSimdInstructions *simd_instructions){} #endif #endif /* CPU_CAPS_H */ aften/libaften/crc.c000066400000000000000000000054061132016273200146540ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * Copyright (c) 2006 Justin Ruggles * * Based on "The simplest AC3 encoder" from FFmpeg * Copyright (c) 2000 Fabrice Bellard. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file crc.c * CRC-16 calculation */ #include "crc.h" #define CRC16_POLY 0x18005 #ifdef WORDS_BIGENDIAN #define LOW_BYTE 1 #define HIGH_BYTE 0 #else #define LOW_BYTE 0 #define HIGH_BYTE 1 #endif union crc_t { uint16_t word; uint8_t bytes[2]; }; static void crc_init_table(uint16_t *table, int bits, int poly) { int i, j, crc; poly = (poly + (1<> 1; b = b << 1; if (b & (1 << 16)) b ^= CRC16_POLY; } return c; } static uint32_t pow_poly(uint32_t n) { uint32_t a = (CRC16_POLY >> 1); uint32_t r = 1; while (n) { if (n & 1) r = mul_poly(r, a); a = mul_poly(a, a); n >>= 1; } return r; } /** * calculates crc value which will result in zero crc * where the crc is the first 2 bytes of the data * @param crc crc16 of all data except 1st 2 crc bytes * @param size total bytes of data, including the crc */ uint16_t crc16_zero(uint16_t crc, int size) { int crc_inv; crc_inv = pow_poly(size*8); crc = mul_poly(crc_inv, crc); return crc; } aften/libaften/crc.h000066400000000000000000000022131132016273200146520ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * Copyright (c) 2006 Justin Ruggles * * Based on "The simplest AC3 encoder" from FFmpeg * Copyright (c) 2000 Fabrice Bellard. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file crc.h * CRC-16 header */ #ifndef CRC_H #define CRC_H #include "common.h" extern void crc_init(void); extern uint16_t calc_crc16(const uint8_t *buf, uint32_t len); extern uint16_t crc16_zero(uint16_t crc, int size); #endif /* CRC_H */ aften/libaften/dynrng.c000066400000000000000000000133711132016273200154060ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * Copyright (c) 2006 Justin Ruggles * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file dynrng.c * A/52 Dynamic Range Compression */ #include "a52enc.h" #include "dynrng.h" typedef struct { int boost_start; int null_start; int early_cut_start; int cut_start; int cut_end; FLOAT boost_ratio; FLOAT early_cut_ratio; FLOAT cut_ratio; } DRCProfile; static const DRCProfile drc_profiles[5] = { // Film Light { -22, -10, 10, 20, 35, FCONST(0.50), FCONST(0.50), FCONST(0.05) }, // Film Standard { -12, 0, 5, 15, 35, FCONST(0.50), FCONST(0.50), FCONST(0.05) }, // Music Light { -34, -10, 10, 10, 40, FCONST(0.50), FCONST(0.50), FCONST(0.50) }, // Music Standard { -24, 0, 5, 15, 35, FCONST(0.50), FCONST(0.50), FCONST(0.05) }, // Speech { -19, 0, 5, 15, 35, FCONST(0.20), FCONST(0.50), FCONST(0.05) } }; /** * table of dynrng scale factors indexed by dynrng code * scale factor is given in 1/512 units * 0- 31 : 512 - 1008 step 16 (1.0000 - 1.968750000 step 0.031250000) * 32- 63 : 1024 - 2016 step 32 (2.0000 - 3.937500000 step 0.062500000) * 64- 95 : 2048 - 4032 step 64 (4.0000 - 7.875000000 step 0.125000000) * 96-127 : 4096 - 8064 step 128 (8.0000 - 15.750000000 step 0.250000000) * 128-159 : 32 - 63 step 1 (0.0625 - 0.123046875 step 0.001953125) * 160-191 : 64 - 126 step 2 (0.1250 - 0.246093750 step 0.003906250) * 192-223 : 128 - 252 step 4 (0.2500 - 0.492187500 step 0.007812500) * 224-255 : 256 - 504 step 8 (0.5000 - 0.984375000 step 0.015625000) */ #if 0 static FLOAT dynrngscaletab[256]; #endif #define DB_TO_SCALE(db) (AFT_EXP10(db * FCONST(0.05))) #define SCALE_TO_DB(scale) (FCONST(20.0) * AFT_LOG10(scale)) void dynrng_init(void) { #if 0 int i, logscale; for (i = 0; i < 256; i++) { logscale = ((i >> 5) + 4) & 7; dynrngscaletab[i] = (1 << (logscale+5)) + ((i & 31) << logscale); } #endif } static int scale_to_dynrng(FLOAT scale) { int scale512, logscale, code; scale512 = (int)(AFT_FABS(scale) * FCONST(512.0)); scale512 = CLIP(scale512, 32, 8064); logscale = log2i(scale512)-5; code = (((logscale + 4) & 7) << 5) + ((scale512 - (1 << (logscale+5))) >> logscale); return code; } #if 0 // save for later use static FLOAT dynrng_to_scale(int code) { FLOAT scale; code = CLIP(code, 0, 255); scale = ((FLOAT)dynrngscaletab[code]) / FCONST(512.0); return scale; } #endif /** * Calculates decibel gain which should be applied */ static FLOAT calculate_gain_from_profile(FLOAT rms, int dialnorm, int profile) { DRCProfile ps; FLOAT max_ecut, gain, target; ps = drc_profiles[profile]; ps.boost_start += dialnorm; ps.null_start += dialnorm; ps.early_cut_start += dialnorm; ps.cut_start += dialnorm; ps.cut_end += dialnorm; max_ecut = ps.early_cut_start + ((ps.cut_start - ps.early_cut_start) * ps.early_cut_ratio); gain = 0; if (rms <= ps.boost_start) { gain = (ps.null_start - ps.boost_start) * ps.boost_ratio; } else if (rms <= ps.null_start) { gain = (ps.null_start - rms) * ps.boost_ratio; } else if (rms <= ps.early_cut_start) { gain = 0; } else if (rms <= ps.cut_start) { target = ps.early_cut_start + ((rms - ps.early_cut_start) * ps.early_cut_ratio); gain = target - rms; } else if (rms <= ps.cut_end) { target = max_ecut + ((rms - ps.cut_start) * ps.cut_ratio); gain = target - rms; } else { target = max_ecut + ((ps.cut_end - ps.cut_start) * ps.cut_ratio); gain = target - rms; } return gain; } static FLOAT calculate_rms(FLOAT *samples[A52_MAX_CHANNELS], int ch, int n) { FLOAT rms_all, rms_left, rms_right; int i; // For now, use only the left and right channels to calculate loudness if (ch == 1) { rms_all = 0; for (i = 0; i < n; i++) rms_all += (samples[0][i] * samples[0][i]); rms_all /= n; } else { rms_left = rms_right = 0; for (i = 0; i < n; i++) { rms_left += (samples[0][i] * samples[0][i]); rms_right += (samples[1][i] * samples[1][i]); } rms_all = (rms_left + rms_right) / (FCONST(2.0) * n); } // Convert to dB rms_all = FCONST(10.0) * AFT_LOG10(rms_all + FCONST(1e-10)); return rms_all; } int calculate_block_dynrng(FLOAT *samples[A52_MAX_CHANNELS], int num_ch, int dialnorm, DynRngProfile profile) { int ch, i; FLOAT max_gain, rms, gain; if (profile == DYNRNG_PROFILE_NONE) return 0; // Find the maximum dB gain that can be used without clipping max_gain = 0; for (ch = 0; ch < num_ch; ch++) for (i = 0; i < 256; i++) max_gain = MAX(AFT_FABS(samples[ch][i]), max_gain); max_gain = SCALE_TO_DB(FCONST(1.0) / max_gain); rms = calculate_rms(samples, num_ch, 256); gain = calculate_gain_from_profile(rms, dialnorm, (int)profile); gain = MIN(gain, max_gain); return scale_to_dynrng(DB_TO_SCALE(gain)); } aften/libaften/dynrng.h000066400000000000000000000021261132016273200154070ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * Copyright (c) 2006 Justin Ruggles * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file dynrng.h * A/52 Dynamic Range Compression header */ #ifndef DYNRNG_H #define DYNRNG_H #include "common.h" void dynrng_init(void); int calculate_block_dynrng(FLOAT *samples[A52_MAX_CHANNELS], int num_ch, int dialnorm, DynRngProfile profile); #endif aften/libaften/exponent.c000066400000000000000000000266011132016273200157450ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * Copyright (c) 2006 Justin Ruggles * * Based on "The simplest AC3 encoder" from FFmpeg * Copyright (c) 2000 Fabrice Bellard. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file exponent.c * A/52 exponent functions */ #include "a52enc.h" #include "cpu_caps.h" uint16_t expstr_set_bits[A52_EXPSTR_SETS][256] = {{0}}; /** * Search order for the pre-defined strategy sets. * The sets are arranged to give a good distribution of time domain vs. * frequency domain accuracy with different search sizes. */ static const uint8_t expstr_set_search_order_tab[A52_EXPSTR_SETS] = { 0, 31, 10, 2, 8, 17, 24, 22, 3, 21, 26, 13, 14, 23, 29, 11, 30, 27, 15, 16, 1, 9, 12, 4, 5, 6, 7, 18, 19, 20, 25, 28 }; /** * Determine a good exponent strategy for all blocks of a single channel. * A pre-defined set of strategies is chosen based on the SSE between each set * and the most accurate strategy set (all blocks EXP_D15). */ static int compute_expstr_ch(A52ExponentFunctions *expf, uint8_t *exp[A52_NUM_BLOCKS], int ncoefs, int search_size) { ALIGN16(uint8_t) exponents[A52_NUM_BLOCKS][256]; int blk, s, str, i, j, k; int min_error, exp_error[A52_EXPSTR_SETS]; min_error = expstr_set_search_order_tab[0]; for (s = 0; s < search_size; s++) { str = expstr_set_search_order_tab[s]; // collect exponents for (blk = 0; blk < A52_NUM_BLOCKS; blk++) memcpy(exponents[blk], exp[blk], 256); // encode exponents i = 0; while (i < A52_NUM_BLOCKS) { j = i + 1; while (j < A52_NUM_BLOCKS && a52_expstr_set_tab[str][j]==EXP_REUSE) { expf->exponent_min(exponents[i], exponents[j], ncoefs); j++; } expf->encode_exp_blk_ch(exponents[i], ncoefs, a52_expstr_set_tab[str][i]); for (k = i+1; k < j; k++) memcpy(exponents[k], exponents[i], 256); i = j; } // select strategy based on minimum error from unencoded exponents exp_error[str] = 0; for (blk = 0; blk < A52_NUM_BLOCKS; blk++) { exp_error[str] += expf->exponent_sum_square_error(exp[blk], exponents[blk], ncoefs); } if (exp_error[str] < exp_error[min_error]) min_error = str; } return min_error; } /** * Runs the per-channel exponent strategy decision function for all channels */ static void compute_exponent_strategy(A52ThreadContext *tctx) { A52Context *ctx = tctx->ctx; A52Frame *frame = &tctx->frame; A52Block *blocks = frame->blocks; int *ncoefs = frame->ncoefs; uint8_t *exp[A52_MAX_CHANNELS][A52_NUM_BLOCKS]; int ch, blk, str; for (ch = 0; ch < ctx->n_channels; ch++) { str = expstr_set_search_order_tab[0]; if (ctx->params.expstr_search > 1) { for (blk = 0; blk < A52_NUM_BLOCKS; blk++) exp[ch][blk] = blocks[blk].exp[ch]; str = compute_expstr_ch(&ctx->expf, exp[ch], ncoefs[ch], ctx->params.expstr_search); } for (blk = 0; blk < A52_NUM_BLOCKS; blk++) blocks[blk].exp_strategy[ch] = a52_expstr_set_tab[str][blk]; frame->expstr_set[ch] = str; } // lfe channel if (ctx->lfe) { for (blk = 0; blk < A52_NUM_BLOCKS; blk++) blocks[blk].exp_strategy[ctx->lfe_channel] = !blk ? EXP_D15 : EXP_REUSE; } } /** * Encode exponent groups. 3 exponents are in per 7-bit group. The number of * groups varies depending on exponent strategy and bandwidth */ static void group_exponents(A52ThreadContext *tctx) { A52Context *ctx = tctx->ctx; A52Frame *frame = &tctx->frame; A52Block *block; uint8_t *p; int delta[3]; int blk, ch, i, gsize, bits; int expstr; int exp0, exp1, exp2, exp3; bits = 0; for (blk = 0; blk < A52_NUM_BLOCKS; blk++) { block = &frame->blocks[blk]; for (ch = 0; ch < ctx->n_all_channels; ch++) { expstr = block->exp_strategy[ch]; if (expstr == EXP_REUSE) { block->nexpgrps[ch] = 0; continue; } block->nexpgrps[ch] = nexpgrptab[expstr-1][frame->ncoefs[ch]]; bits += (4 + (block->nexpgrps[ch] * 7)); gsize = expstr + (expstr == EXP_D45); p = block->exp[ch]; exp1 = *p++; block->grp_exp[ch][0] = exp1; for (i = 1; i <= block->nexpgrps[ch]; i++) { /* merge three delta into one code */ exp0 = exp1; exp1 = p[0]; p += gsize; delta[0] = exp1 - exp0 + 2; exp2 = p[0]; p += gsize; delta[1] = exp2 - exp1 + 2; exp3 = p[0]; p += gsize; delta[2] = exp3 - exp2 + 2; exp1 = exp3; block->grp_exp[ch][i] = ((delta[0]*5+delta[1])*5)+delta[2]; } } } frame->exp_bits = bits; } /** * Creates final exponents for the entire frame based on exponent strategies. * If the strategy for a block & channel is EXP_REUSE, exponents are copied, * otherwise they are encoded according to the specific exponent strategy. */ static void encode_exponents(A52ThreadContext *tctx) { A52Context *ctx = tctx->ctx; A52Frame *frame = &tctx->frame; A52Block *blocks = frame->blocks; int *ncoefs = frame->ncoefs; int ch, i, j, k; for (ch = 0; ch < ctx->n_all_channels; ch++) { // compute the exponents as the decoder will see them. The // EXP_REUSE case must be handled carefully : we select the // min of the exponents i = 0; while (i < A52_NUM_BLOCKS) { j = i + 1; while (j < A52_NUM_BLOCKS && blocks[j].exp_strategy[ch]==EXP_REUSE) { ctx->expf.exponent_min(blocks[i].exp[ch], blocks[j].exp[ch], ncoefs[ch]); j++; } ctx->expf.encode_exp_blk_ch(blocks[i].exp[ch], ncoefs[ch], blocks[i].exp_strategy[ch]); // copy encoded exponents for reuse case for (k = i+1; k < j; k++) memcpy(blocks[k].exp[ch], blocks[i].exp[ch], ncoefs[ch]); i = j; } } } /** * Extracts the optimal exponent portion of each MDCT coefficient. */ static void extract_exponents(A52ThreadContext *tctx) { A52Frame *frame = &tctx->frame; A52Block *block; int all_channels = tctx->ctx->n_all_channels; int blk, ch, j; uint32_t v1, v2; for (ch = 0; ch < all_channels; ch++) { for (blk = 0; blk < A52_NUM_BLOCKS; blk++) { block = &frame->blocks[blk]; for (j = 0; j < 256; j += 2) { v1 = (uint32_t)AFT_FABS(block->mdct_coef[ch][j ] * FCONST(16777216.0)); v2 = (uint32_t)AFT_FABS(block->mdct_coef[ch][j+1] * FCONST(16777216.0)); block->exp[ch][j ] = (v1 == 0)? 24 : 23 - log2i(v1); block->exp[ch][j+1] = (v2 == 0)? 24 : 23 - log2i(v2); } } } } static void exponent_min(uint8_t *exp, uint8_t *exp1, int n) { int i; for (i = 0; i < n; i++) exp[i] = MIN(exp[i], exp1[i]); } static void encode_exp_blk_ch(uint8_t *exp, int ncoefs, int exp_strategy) { int i, k; int ngrps; int exp_min1, exp_min2; ngrps = nexpgrptab[exp_strategy-1][ncoefs] * 3; // constraint for DC exponent exp[0] = MIN(exp[0], 15); // for each group, compute the minimum exponent switch (exp_strategy) { case EXP_D25: for (i = 1, k = 1; i <= ngrps; i++) { exp[i] = MIN(exp[k], exp[k+1]); k += 2; } break; case EXP_D45: for (i = 1, k = 1; i <= ngrps; i++) { exp_min1 = MIN(exp[k ], exp[k+1]); exp_min2 = MIN(exp[k+2], exp[k+3]); exp[i] = MIN(exp_min1, exp_min2); k += 4; } break; } // Decrease the delta between each groups to within 2 // so that they can be differentially encoded for (i = 1; i <= ngrps; i++) exp[i] = MIN(exp[i], exp[i-1]+2); for (i = ngrps-1; i >= 0; i--) exp[i] = MIN(exp[i], exp[i+1]+2); // expand exponent groups to generate final set of exponents switch (exp_strategy) { case EXP_D25: for (i = ngrps, k = ngrps*2; i > 0; i--) { exp[k] = exp[k-1] = exp[i]; k -= 2; } break; case EXP_D45: for (i = ngrps, k = ngrps*4; i > 0; i--) { exp[k] = exp[k-1] = exp[k-2] = exp[k-3] = exp[i]; k -= 4; } break; } } static int exponent_sum_square_error(uint8_t *exp0, uint8_t *exp1, int ncoefs) { int i, err; int exp_error = 0; for (i = 0; i < ncoefs; i++) { err = exp0[i] - exp1[i]; exp_error += (err * err); } return exp_error; } /** * Runs all the processes in extracting, analyzing, and encoding exponents */ void a52_process_exponents(A52ThreadContext *tctx) { extract_exponents(tctx); compute_exponent_strategy(tctx); encode_exponents(tctx); group_exponents(tctx); } /** * Initialize exponent group size table */ void exponent_init(A52ExponentFunctions *expf) { int i, j, grpsize, ngrps, nc, blk; for (i = 1; i < 4; i++) { for (j = 0; j < 256; j++) { grpsize = i + (i == EXP_D45); ngrps = 0; if (j == 7) ngrps = 2; else ngrps = (j + (grpsize * 3) - 4) / (3 * grpsize); nexpgrptab[i-1][j] = ngrps; } } for (i = 0; i < 6; i++) { uint16_t *expbits = expstr_set_bits[i]; for (nc = 0; nc <= 253; nc++) { uint16_t bits = 0; for (blk = 0; blk < A52_NUM_BLOCKS; blk++) { uint8_t es = a52_expstr_set_tab[i][blk]; if (es != EXP_REUSE) bits += (4 + (nexpgrptab[es-1][nc] * 7)); } expbits[nc] = bits; } } expf->exponent_min = exponent_min; expf->encode_exp_blk_ch = encode_exp_blk_ch; expf->exponent_sum_square_error = exponent_sum_square_error; #ifdef HAVE_MMX if (cpu_caps_have_mmx()) { expf->exponent_min = exponent_min_mmx; expf->encode_exp_blk_ch = encode_exp_blk_ch_mmx; expf->exponent_sum_square_error = exponent_sum_square_error_mmx; } #endif /* HAVE_MMX */ #ifdef HAVE_SSE2 if (cpu_caps_have_sse2()) { expf->exponent_min = exponent_min_sse2; expf->encode_exp_blk_ch = encode_exp_blk_ch_sse2; expf->exponent_sum_square_error = exponent_sum_square_error_sse2; } #endif /* HAVE_SSE2 */ } aften/libaften/exponent.h000066400000000000000000000037431132016273200157540ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * Copyright (c) 2006 Justin Ruggles * * Based on "The simplest AC3 encoder" from FFmpeg * Copyright (c) 2000 Fabrice Bellard. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file exponent.h * A/52 exponent header */ #ifndef EXPONENT_H #define EXPONENT_H #include "common.h" #if defined(HAVE_MMX) || defined(HAVE_SSE) #include "x86/exponent.h" #endif struct A52ThreadContext; #define A52_EXPSTR_SETS 32 extern int nexpgrptab[3][256]; extern uint16_t expstr_set_bits[A52_EXPSTR_SETS][256]; typedef struct A52ExponentFunctions { /** Set exp[i] to min(exp[i], exp1[i]) */ void (*exponent_min)(uint8_t *exp, uint8_t *exp1, int n); /** * Update the exponents so that they are the ones the decoder will decode. * Constrain DC exponent, group exponents based on strategy, constrain delta * between adjacent exponents to +2/-2. */ void (*encode_exp_blk_ch)(uint8_t *exp, int ncoefs, int exp_strategy); /** * Calculate sum of squared error between 2 sets of exponents. */ int (*exponent_sum_square_error)(uint8_t *exp0, uint8_t *exp1, int ncoefs); } A52ExponentFunctions; extern void exponent_init(A52ExponentFunctions *expf); extern void a52_process_exponents(struct A52ThreadContext *tctx); #endif /* EXPONENT_H */ aften/libaften/filter.c000066400000000000000000000223401132016273200153660ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * Copyright (c) 2006 Justin Ruggles * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file filter.c * Audio filters */ #include "filter.h" typedef struct Filter { const char *name; enum FilterID id; int private_size; int (*init)(FilterContext *f); void (*filter)(FilterContext *f, FLOAT *out, FLOAT *in, int n); } Filter; typedef struct { FLOAT coefs[5]; FLOAT state[2][5]; } BiquadContext; static void biquad_generate_lowpass(BiquadContext *f, FLOAT fc) { FLOAT omega, alpha, cs; FLOAT a[3], b[3]; omega = FCONST(2.0) * AFT_PI * fc; alpha = AFT_SIN(omega) / FCONST(2.0); cs = AFT_COS(omega); a[0] = FCONST(1.0) + alpha; a[1] = -FCONST(2.0) * cs; a[2] = FCONST(1.0) - alpha; b[0] = (FCONST(1.0) - cs) / FCONST(2.0); b[1] = (FCONST(1.0) - cs); b[2] = (FCONST(1.0) - cs) / FCONST(2.0); f->coefs[0] = b[0] / a[0]; f->coefs[1] = b[1] / a[0]; f->coefs[2] = b[2] / a[0]; f->coefs[3] = a[1] / a[0]; f->coefs[4] = a[2] / a[0]; } static void biquad_generate_highpass(BiquadContext *f, FLOAT fc) { FLOAT omega, alpha, cs; FLOAT a[3], b[3]; omega = FCONST(2.0) * AFT_PI * fc; alpha = AFT_SIN(omega) / FCONST(2.0); cs = AFT_COS(omega); a[0] = FCONST(1.0) + alpha; a[1] = -FCONST(2.0) * cs; a[2] = FCONST(1.0) - alpha; b[0] = (FCONST(1.0) + cs) / FCONST(2.0); b[1] = -(FCONST(1.0) + cs); b[2] = (FCONST(1.0) + cs) / FCONST(2.0); f->coefs[0] = b[0] / a[0]; f->coefs[1] = b[1] / a[0]; f->coefs[2] = b[2] / a[0]; f->coefs[3] = a[1] / a[0]; f->coefs[4] = a[2] / a[0]; } static int biquad_init(FilterContext *f) { int i, j; BiquadContext *b = f->private_context; FLOAT fc; if (f->samplerate <= 0) return -1; if (f->cutoff < 0 || f->cutoff > (f->samplerate/FCONST(2.0))) return -1; fc = f->cutoff / f->samplerate; if (f->type == FILTER_TYPE_LOWPASS) biquad_generate_lowpass(b, fc); else if (f->type == FILTER_TYPE_HIGHPASS) biquad_generate_highpass(b, fc); else return -1; for (j = 0; j < 2; j++) for (i = 0; i < 5; i++) b->state[j][i] = 0.0; return 0; } static void biquad_i_run_filter(FilterContext *f, FLOAT *out, FLOAT *in, int n) { BiquadContext *b = f->private_context; FLOAT *coefs = b->coefs; FLOAT *tmp = in; int i, j; for (j = 0; j < 1+f->cascaded; j++) { FLOAT *state_j = b->state[j]; for (i = 0; i < n; i++) { FLOAT v = 0; state_j[0] = tmp[i]; v += coefs[0] * state_j[0]; v += coefs[1] * state_j[1]; v += coefs[2] * state_j[2]; v -= coefs[3] * state_j[3]; v -= coefs[4] * state_j[4]; state_j[2] = state_j[1]; state_j[4] = state_j[3]; state_j[1] = state_j[0]; state_j[3] = v; out[i] = CLIP(v, -FCONST(1.0), FCONST(1.0)); } tmp = out; } } static void biquad_ii_run_filter(FilterContext *f, FLOAT *out, FLOAT *in, int n) { BiquadContext *b = f->private_context; FLOAT *coefs = b->coefs; FLOAT *tmp = in; int i, j; FLOAT v; for (j = 0; j < 1+f->cascaded; j++) { FLOAT *state_j = b->state[j]; for (i = 0; i < n; i++) { state_j[0] = tmp[i]; v = coefs[0] * state_j[0] + state_j[1]; state_j[1] = coefs[1] * state_j[0] - coefs[3] * v + state_j[2]; state_j[2] = coefs[2] * state_j[0] - coefs[4] * v; out[i] = CLIP(v, -FCONST(1.0), FCONST(1.0)); } tmp = out; } } static const Filter biquad_i_filter = { "Biquad Direct Form I", FILTER_ID_BIQUAD_I, sizeof(BiquadContext), biquad_init, biquad_i_run_filter, }; static const Filter biquad_ii_filter = { "Biquad Direct Form II", FILTER_ID_BIQUAD_II, sizeof(BiquadContext), biquad_init, biquad_ii_run_filter, }; static void butterworth_generate_lowpass(BiquadContext *f, FLOAT fc) { FLOAT c = FCONST(1.0) / AFT_TAN(AFT_PI * fc); FLOAT c2 = (c * c); f->coefs[0] = FCONST(1.0) / (c2 + AFT_SQRT2 * c + FCONST(1.0)); f->coefs[1] = FCONST(2.0) * f->coefs[0]; f->coefs[2] = f->coefs[0]; f->coefs[3] = FCONST(2.0) * (FCONST(1.0) - c2) * f->coefs[0]; f->coefs[4] = (c2 - AFT_SQRT2 * c + FCONST(1.0)) * f->coefs[0]; } static void butterworth_generate_highpass(BiquadContext *f, FLOAT fc) { FLOAT c = AFT_TAN(AFT_PI * fc); FLOAT c2 = (c * c); f->coefs[0] = FCONST(1.0) / (c2 + AFT_SQRT2 * c + FCONST(1.0)); f->coefs[1] = -FCONST(2.0) * f->coefs[0]; f->coefs[2] = f->coefs[0]; f->coefs[3] = FCONST(2.0) * (c2 - FCONST(1.0)) * f->coefs[0]; f->coefs[4] = (c2 - AFT_SQRT2 * c + FCONST(1.0)) * f->coefs[0]; } static int butterworth_init(FilterContext *f) { int i, j; BiquadContext *b = f->private_context; FLOAT fc; if (f->samplerate <= 0) return -1; if (f->cutoff < 0 || f->cutoff > (f->samplerate/FCONST(2.0))) return -1; fc = f->cutoff / f->samplerate; if (f->type == FILTER_TYPE_LOWPASS) butterworth_generate_lowpass(b, fc); else if (f->type == FILTER_TYPE_HIGHPASS) butterworth_generate_highpass(b, fc); else return -1; for (j = 0; j < 2; j++) for (i = 0; i < 5; i++) b->state[j][i] = 0.0; return 0; } static const Filter butterworth_i_filter = { "Butterworth Direct Form I", FILTER_ID_BUTTERWORTH_I, sizeof(BiquadContext), butterworth_init, biquad_i_run_filter, }; static const Filter butterworth_ii_filter = { "Butterworth Direct Form II", FILTER_ID_BUTTERWORTH_II, sizeof(BiquadContext), butterworth_init, biquad_ii_run_filter, }; /* One-pole, One-zero filter */ typedef struct { FLOAT p; FLOAT last; } OnePoleContext; static void onepole_generate_lowpass(OnePoleContext *o, FLOAT fc) { FLOAT omega, cs; omega = FCONST(2.0) * AFT_PI * fc; cs = FCONST(2.0) - AFT_COS(omega); o->p = cs - AFT_SQRT((cs*cs)-FCONST(1.0)); o->last = 0.0; } static void onepole_generate_highpass(OnePoleContext *o, FLOAT fc) { FLOAT omega, cs; omega = FCONST(2.0) * AFT_PI * fc; cs = FCONST(2.0) + AFT_COS(omega); o->p = cs - AFT_SQRT((cs*cs)-FCONST(1.0)); o->last = 0.0; } static int onepole_init(FilterContext *f) { OnePoleContext *o = f->private_context; FLOAT fc; if (f->cascaded) return -1; if (f->samplerate <= 0) return -1; if (f->cutoff < 0 || f->cutoff > (f->samplerate/FCONST(2.0))) return -1; fc = f->cutoff / f->samplerate; if (f->type == FILTER_TYPE_LOWPASS) onepole_generate_lowpass(o, fc); else if (f->type == FILTER_TYPE_HIGHPASS) onepole_generate_highpass(o, fc); else return -1; return 0; } static void onepole_run_filter(FilterContext *f, FLOAT *out, FLOAT *in, int n) { int i; FLOAT v; FLOAT p1 = 0; OnePoleContext *o = f->private_context; if (f->type == FILTER_TYPE_LOWPASS) p1 = FCONST(1.0) - o->p; else if(f->type == FILTER_TYPE_HIGHPASS) p1 = o->p - FCONST(1.0); for (i = 0; i < n; i++) { v = (p1 * in[i]) + (o->p * o->last); o->last = out[i] = CLIP(v, -FCONST(1.0), FCONST(1.0)); } } static const Filter onepole_filter = { "One-Pole Filter", FILTER_ID_ONEPOLE, sizeof(OnePoleContext), onepole_init, onepole_run_filter, }; int filter_init(FilterContext *f, enum FilterID id) { if(f == NULL) return -1; switch (id) { case FILTER_ID_BIQUAD_I: f->filter = &biquad_i_filter; break; case FILTER_ID_BIQUAD_II: f->filter = &biquad_ii_filter; break; case FILTER_ID_BUTTERWORTH_I: f->filter = &butterworth_i_filter; break; case FILTER_ID_BUTTERWORTH_II: f->filter = &butterworth_ii_filter; break; case FILTER_ID_ONEPOLE: f->filter = &onepole_filter; break; default: return -1; } f->private_context = calloc(f->filter->private_size, 1); return f->filter->init(f); } void filter_run(FilterContext *f, FLOAT *out, FLOAT *in, int n) { f->filter->filter(f, out, in, n); } void filter_close(FilterContext *f) { if (!f) return; if (f->private_context) { free(f->private_context); f->private_context = NULL; } f->filter = NULL; } aften/libaften/filter.h000066400000000000000000000031641132016273200153760ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * Copyright (c) 2006 Justin Ruggles * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file filter.h * Audio filters header */ #ifndef FILTER_H #define FILTER_H #include "common.h" enum FilterType { FILTER_TYPE_LOWPASS, FILTER_TYPE_HIGHPASS, FILTER_TYPE_BANDPASS, FILTER_TYPE_BANDSTOP, FILTER_TYPE_ALLPASS, }; enum FilterID { FILTER_ID_BIQUAD_I, FILTER_ID_BIQUAD_II, FILTER_ID_BUTTERWORTH_I, FILTER_ID_BUTTERWORTH_II, FILTER_ID_ONEPOLE, }; struct Filter; typedef struct { const struct Filter *filter; void *private_context; enum FilterType type; int cascaded; FLOAT cutoff; FLOAT cutoff2; FLOAT samplerate; int taps; } FilterContext; extern int filter_init(FilterContext *f, enum FilterID id); extern void filter_run(FilterContext *f, FLOAT *out, FLOAT *in, int n); extern void filter_close(FilterContext *f); #endif /* FILTER_H */ aften/libaften/mdct.c000066400000000000000000000401601132016273200150300ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * * This file is derived from libvorbis * Copyright (c) 2002, 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. */ /** * @file mdct.c * Modified Discrete Cosine Transform */ #include "a52enc.h" #include "mdct.h" #include "cpu_caps.h" #include "mem.h" /** * Allocates and initializes lookup tables in the MDCT context. * @param mdct The MDCT context * @param n Number of time-domain samples used in the MDCT transform */ void mdct_ctx_init(MDCTContext *mdct, int n) { int *bitrev = aligned_malloc((n/4) * sizeof(int)); FLOAT *trig = aligned_malloc((n+n/4) * sizeof(FLOAT)); int i; int n2 = (n >> 1); int log2n = mdct->log2n = log2i(n); mdct->n = n; mdct->trig = trig; mdct->bitrev = bitrev; // trig lookups for (i = 0; i < n/4; i++) { trig[i*2] = AFT_COS((AFT_PI/n)*(4*i)); trig[i*2+1] = -AFT_SIN((AFT_PI/n)*(4*i)); trig[n2+i*2] = AFT_COS((AFT_PI/(2*n))*(2*i+1)); trig[n2+i*2+1] = AFT_SIN((AFT_PI/(2*n))*(2*i+1)); } for (i = 0; i < n/8; i++) { trig[n+i*2] = AFT_COS((AFT_PI/n)*(4*i+2))*FCONST(0.5); trig[n+i*2+1] = -AFT_SIN((AFT_PI/n)*(4*i+2))*FCONST(0.5); } // bitreverse lookup { int j, acc; int mask = (1 << (log2n-1)) - 1; int msb = (1 << (log2n-2)); for (i = 0; i < n/8; i++) { acc = 0; for (j = 0; msb>>j; j++) { if ((msb>>j) & i) acc |= (1 << j); } bitrev[i*2]= ((~acc) & mask) - 1; bitrev[i*2+1] = acc; } } // MDCT scale used in AC3 mdct->scale = FCONST(-2.0) / n; } /** Deallocates memory use by the lookup tables in the MDCT context. */ static void mdct_ctx_close(MDCTContext *mdct) { if (mdct) { if (mdct->trig) aligned_free(mdct->trig); if (mdct->bitrev) aligned_free(mdct->bitrev); #ifndef CONFIG_DOUBLE #ifdef HAVE_SSE if (mdct->trig_bitreverse) aligned_free(mdct->trig_bitreverse); if (mdct->trig_forward) aligned_free(mdct->trig_forward); if (mdct->trig_butterfly_first) aligned_free(mdct->trig_butterfly_first); if (mdct->trig_butterfly_generic8) aligned_free(mdct->trig_butterfly_generic8); if (mdct->trig_butterfly_generic16) aligned_free(mdct->trig_butterfly_generic16); if (mdct->trig_butterfly_generic32) aligned_free(mdct->trig_butterfly_generic32); if (mdct->trig_butterfly_generic64) aligned_free(mdct->trig_butterfly_generic64); #endif #endif memset(mdct, 0, sizeof(MDCTContext)); } } /** Allocates internal buffers for MDCT calculation. */ static void mdct_tctx_init(MDCTThreadContext *tmdct, int n) { tmdct->buffer = aligned_malloc((n+2) * sizeof(FLOAT)); /* +2 to prevent illegal read in bitreverse */ tmdct->buffer1 = aligned_malloc( n * sizeof(FLOAT)); } /** Deallocates internal buffers for MDCT calculation. */ static void tctx_close(MDCTThreadContext *tmdct) { if (tmdct) { if(tmdct->buffer) aligned_free(tmdct->buffer); if(tmdct->buffer1) aligned_free(tmdct->buffer1); } } /** 8 point butterfly (in place, 4 register) */ static inline void mdct_butterfly_8(FLOAT *x) { FLOAT r0 = x[6] + x[2]; FLOAT r1 = x[6] - x[2]; FLOAT r2 = x[4] + x[0]; FLOAT r3 = x[4] - x[0]; x[6] = r0 + r2; x[4] = r0 - r2; r0 = x[5] - x[1]; r2 = x[7] - x[3]; x[0] = r1 + r0; x[2] = r1 - r0; r0 = x[5] + x[1]; r1 = x[7] + x[3]; x[3] = r2 + r3; x[1] = r2 - r3; x[7] = r1 + r0; x[5] = r1 - r0; } /** 16 point butterfly (in place, 4 register) */ static inline void mdct_butterfly_16(FLOAT *x) { FLOAT r0 = x[1] - x[9]; FLOAT r1 = x[0] - x[8]; x[8] += x[0]; x[9] += x[1]; x[0] = ((r0 + r1) * AFT_PI2_8); x[1] = ((r0 - r1) * AFT_PI2_8); r0 = x[3] - x[11]; r1 = x[10] - x[2]; x[10] += x[2]; x[11] += x[3]; x[2] = r0; x[3] = r1; r0 = x[12] - x[4]; r1 = x[13] - x[5]; x[12] += x[4]; x[13] += x[5]; x[4] = ((r0 - r1) * AFT_PI2_8); x[5] = ((r0 + r1) * AFT_PI2_8); r0 = x[14] - x[6]; r1 = x[15] - x[7]; x[14] += x[6]; x[15] += x[7]; x[6] = r0; x[7] = r1; mdct_butterfly_8(x); mdct_butterfly_8(x+8); } /** 32 point butterfly (in place, 4 register) */ static inline void mdct_butterfly_32(FLOAT *x) { FLOAT r0 = x[30] - x[14]; FLOAT r1 = x[31] - x[15]; x[30] += x[14]; x[31] += x[15]; x[14] = r0; x[15] = r1; r0 = x[28] - x[12]; r1 = x[29] - x[13]; x[28] += x[12]; x[29] += x[13]; x[12] = (r0 * AFT_PI1_8 - r1 * AFT_PI3_8); x[13] = (r0 * AFT_PI3_8 + r1 * AFT_PI1_8); r0 = x[26] - x[10]; r1 = x[27] - x[11]; x[26] += x[10]; x[27] += x[11]; x[10] = ((r0 - r1) * AFT_PI2_8); x[11] = ((r0 + r1) * AFT_PI2_8); r0 = x[24] - x[8]; r1 = x[25] - x[9]; x[24] += x[8]; x[25] += x[9]; x[8] = (r0 * AFT_PI3_8 - r1 * AFT_PI1_8); x[9] = (r1 * AFT_PI3_8 + r0 * AFT_PI1_8); r0 = x[22] - x[6]; r1 = x[7] - x[23]; x[22] += x[6]; x[23] += x[7]; x[6] = r1; x[7] = r0; r0 = x[4] - x[20]; r1 = x[5] - x[21]; x[20] += x[4]; x[21] += x[5]; x[4] = (r1 * AFT_PI1_8 + r0 * AFT_PI3_8); x[5] = (r1 * AFT_PI3_8 - r0 * AFT_PI1_8); r0 = x[2] - x[18]; r1 = x[3] - x[19]; x[18] += x[2]; x[19] += x[3]; x[2] = ((r1 + r0) * AFT_PI2_8); x[3] = ((r1 - r0) * AFT_PI2_8); r0 = x[0] - x[16]; r1 = x[1] - x[17]; x[16] += x[0]; x[17] += x[1]; x[0] = (r1 * AFT_PI3_8 + r0 * AFT_PI1_8); x[1] = (r1 * AFT_PI1_8 - r0 * AFT_PI3_8); mdct_butterfly_16(x); mdct_butterfly_16(x+16); } /** N-point first stage butterfly (in place, 2 register) */ static inline void mdct_butterfly_first(FLOAT *trig, FLOAT *x, int points) { FLOAT *x1 = x + points - 8; FLOAT *x2 = x + (points>>1) - 8; FLOAT r0; FLOAT r1; do { r0 = x1[6] - x2[6]; r1 = x1[7] - x2[7]; x1[6] += x2[6]; x1[7] += x2[7]; x2[6] = (r1 * trig[1] + r0 * trig[0]); x2[7] = (r1 * trig[0] - r0 * trig[1]); r0 = x1[4] - x2[4]; r1 = x1[5] - x2[5]; x1[4] += x2[4]; x1[5] += x2[5]; x2[4] = (r1 * trig[5] + r0 * trig[4]); x2[5] = (r1 * trig[4] - r0 * trig[5]); r0 = x1[2] - x2[2]; r1 = x1[3] - x2[3]; x1[2] += x2[2]; x1[3] += x2[3]; x2[2] = (r1 * trig[9] + r0 * trig[8]); x2[3] = (r1 * trig[8] - r0 * trig[9]); r0 = x1[0] - x2[0]; r1 = x1[1] - x2[1]; x1[0] += x2[0]; x1[1] += x2[1]; x2[0] = (r1 * trig[13] + r0 * trig[12]); x2[1] = (r1 * trig[12] - r0 * trig[13]); x1 -= 8; x2 -= 8; trig += 16; } while (x2 >= x); } /** N/stage point generic N stage butterfly (in place, 2 register) */ static inline void mdct_butterfly_generic(FLOAT *trig, FLOAT *x, int points, int trigint) { FLOAT *x1 = x + points - 8; FLOAT *x2 = x + (points>>1) - 8; FLOAT r0; FLOAT r1; do { r0 = x1[6] - x2[6]; r1 = x1[7] - x2[7]; x1[6] += x2[6]; x1[7] += x2[7]; x2[6] = (r1 * trig[1] + r0 * trig[0]); x2[7] = (r1 * trig[0] - r0 * trig[1]); trig += trigint; r0 = x1[4] - x2[4]; r1 = x1[5] - x2[5]; x1[4] += x2[4]; x1[5] += x2[5]; x2[4] = (r1 * trig[1] + r0 * trig[0]); x2[5] = (r1 * trig[0] - r0 * trig[1]); trig += trigint; r0 = x1[2] - x2[2]; r1 = x1[3] - x2[3]; x1[2] += x2[2]; x1[3] += x2[3]; x2[2] = (r1 * trig[1] + r0 * trig[0]); x2[3] = (r1 * trig[0] - r0 * trig[1]); trig += trigint; r0 = x1[0] - x2[0]; r1 = x1[1] - x2[1]; x1[0] += x2[0]; x1[1] += x2[1]; x2[0] = (r1 * trig[1] + r0 * trig[0]); x2[1] = (r1 * trig[0] - r0 * trig[1]); trig += trigint; x1 -= 8; x2 -= 8; } while (x2 >= x); } static inline void mdct_butterflies(MDCTContext *mdct, FLOAT *x, int points) { FLOAT *trig = mdct->trig; int stages = mdct->log2n-5; int i, j; if (--stages > 0) mdct_butterfly_first(trig, x, points); for (i = 1; --stages > 0; i++) for (j = 0; j < (1<>i)*j, points>>i, 4<n; int *bit = mdct->bitrev; FLOAT *w0 = x; FLOAT *w1 = x = w0+(n>>1); FLOAT *trig = mdct->trig+n; do { FLOAT *x0 = x+bit[0]; FLOAT *x1 = x+bit[1]; FLOAT r0 = x0[1]- x1[1]; FLOAT r1 = x0[0]+ x1[0]; FLOAT r2 = (r1 * trig[0] + r0 * trig[1]); FLOAT r3 = (r1 * trig[1] - r0 * trig[0]); w1 -= 4; r0 = (x0[1] + x1[1]) * FCONST(0.5); r1 = (x0[0] - x1[0]) * FCONST(0.5); w0[0] = r0 + r2; w1[2] = r0 - r2; w0[1] = r1 + r3; w1[3] = r3 - r1; x0 = x+bit[2]; x1 = x+bit[3]; r0 = x0[1] - x1[1]; r1 = x0[0] + x1[0]; r2 = (r1 * trig[2] + r0 * trig[3]); r3 = (r1 * trig[3] - r0 * trig[2]); r0 = (x0[1] + x1[1]) * FCONST(0.5); r1 = (x0[0] - x1[0]) * FCONST(0.5); w0[2] = r0 + r2; w1[0] = r0 - r2; w0[3] = r1 + r3; w1[1] = r3 - r1; trig += 4; bit += 4; w0 += 4; } while (w0 < w1); } static void mdct(MDCTThreadContext *tmdct, FLOAT *out, FLOAT *in) { MDCTContext *mdct = tmdct->mdct; int n = mdct->n; int n2 = n>>1; int n4 = n>>2; int n8 = n>>3; FLOAT *w = tmdct->buffer; FLOAT *w2 = w+n2; FLOAT *x0 = in+n2+n4; FLOAT *x1 = x0+1; FLOAT *trig = mdct->trig + n2; FLOAT r0; FLOAT r1; int i; for (i = 0; i < n8; i += 2) { x0 -= 4; trig -= 2; r0 = x0[2] + x1[0]; r1 = x0[0] + x1[2]; w2[i] = (r1*trig[1] + r0*trig[0]); w2[i+1] = (r1*trig[0] - r0*trig[1]); x1 += 4; } x1 = in+1; for (; i < n2-n8; i += 2) { trig -= 2; x0 -= 4; r0 = x0[2] - x1[0]; r1 = x0[0] - x1[2]; w2[i] = (r1*trig[1] + r0*trig[0]); w2[i+1] = (r1*trig[0] - r0*trig[1]); x1 += 4; } x0 = in+n; for (; i < n2; i += 2) { trig -= 2; x0 -= 4; r0 = -x0[2] - x1[0]; r1 = -x0[0] - x1[2]; w2[i] = (r1*trig[1] + r0*trig[0]); w2[i+1] = (r1*trig[0] - r0*trig[1]); x1 += 4; } mdct_butterflies(mdct, w2, n2); mdct_bitreverse(mdct, w); trig = mdct->trig+n2; x0 = out+n2; for (i = 0; i < n4; i++) { x0--; out[i] = ((w[0]*trig[0]+w[1]*trig[1])*mdct->scale); x0[0] = ((w[0]*trig[1]-w[1]*trig[0])*mdct->scale); w += 2; trig += 2; } } static void mdct_512(A52ThreadContext *tctx, FLOAT *out, FLOAT *in) { mdct(&tctx->mdct_tctx_512, out, in); } #if 0 /** brute-force 256-point MDCT for reference purposes */ static void mdct_256(A52Context *ctx, FLOAT *out, FLOAT *in) { int k, n; FLOAT s, a; FLOAT pi_128 = AFT_PI / 128.0; FLOAT half = 0.5; for (k = 0; k < 128; k++) { s = 0; for (n = 0; n < 256; n++) { a = pi_128 * (n+half) * (k+half); s += in[n] * AFT_COS(a); } out[k*2] = s / -128.0; } for (k = 0; k < 128; k++) { s = 0; for (n = 0; n < 256; n++) { a = pi_128 * (n+half) * (k+half) + AFT_PI * (k+half); s += in[n+256] * AFT_COS(a); } out[2*k+1] = s / -128.0; } } #else static void mdct_256(A52ThreadContext *tctx, FLOAT *out, FLOAT *in) { FLOAT *coef_a = in; FLOAT *coef_b = in+128; FLOAT *xx = tctx->mdct_tctx_256.buffer1; int i; memcpy(xx, in+64, 192 * sizeof(FLOAT)); for (i = 0; i < 64; i++) xx[i+192] = -in[i]; mdct(&tctx->mdct_tctx_256, coef_a, xx); for (i = 0; i < 64; i++) xx[i] = -in[i+256+192]; memcpy(xx+64, in+256, 128 * sizeof(FLOAT)); for (i = 0; i < 64; i++) xx[i+192] = -in[i+256+128]; mdct(&tctx->mdct_tctx_256, coef_b, xx); for (i = 0; i < 128; i++) { out[2*i ] = coef_a[i]; out[2*i+1] = coef_b[i]; } } #endif static void alloc_block_buffers(A52ThreadContext *tctx) { A52Frame *frame = &tctx->frame; int i, j; // we alloced one continous block and // now interleave in and out buffers for (i = 0; i < A52_NUM_BLOCKS; i++) { if (i) { frame->blocks[i].input_samples[0] = frame->blocks[i-1].input_samples[A52_MAX_CHANNELS-1] + 512 + 256; } frame->blocks[i].mdct_coef[0] = frame->blocks[i].input_samples[0] + 512; for (j = 1; j < A52_MAX_CHANNELS; j++) { frame->blocks[i].input_samples[j] = frame->blocks[i].input_samples[j-1] + 512 + 256; frame->blocks[i].mdct_coef[j] = frame->blocks[i].mdct_coef[j-1] + 512 + 256; } } } void mdct_close(A52Context *ctx) { mdct_ctx_close(&ctx->mdct_ctx_512); mdct_ctx_close(&ctx->mdct_ctx_256); } void mdct_thread_close(A52ThreadContext *tctx) { tctx_close(&tctx->mdct_tctx_512); tctx_close(&tctx->mdct_tctx_256); aligned_free(tctx->frame.blocks[0].input_samples[0]); } void mdct_init(A52Context *ctx) { #ifndef CONFIG_DOUBLE #ifdef HAVE_SSE3 if (cpu_caps_have_sse3()) { mdct_init_sse3(ctx); return; } #endif #ifdef HAVE_SSE if (cpu_caps_have_sse()) { mdct_init_sse(ctx); return; } #endif #ifdef HAVE_ALTIVEC if (cpu_caps_have_altivec()) { mdct_init_altivec(ctx); return; } #endif #endif /* CONFIG_DOUBLE */ mdct_ctx_init(&ctx->mdct_ctx_512, 512); mdct_ctx_init(&ctx->mdct_ctx_256, 256); ctx->mdct_ctx_512.mdct = mdct_512; ctx->mdct_ctx_256.mdct = mdct_256; } void mdct_thread_init(A52ThreadContext *tctx) { mdct_tctx_init(&tctx->mdct_tctx_512, 512); mdct_tctx_init(&tctx->mdct_tctx_256, 256); tctx->mdct_tctx_512.mdct = &tctx->ctx->mdct_ctx_512; tctx->mdct_tctx_256.mdct = &tctx->ctx->mdct_ctx_256; tctx->frame.blocks[0].input_samples[0] = aligned_malloc(A52_NUM_BLOCKS * A52_MAX_CHANNELS * (256 + 512) * sizeof(FLOAT)); alloc_block_buffers(tctx); } aften/libaften/mdct.h000066400000000000000000000062531132016273200150420ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * * This file is derived from libvorbis * Copyright (c) 2002, 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. */ /** * @file mdct.h * MDCT header */ #ifndef MDCT_H #define MDCT_H #include "common.h" #if defined(HAVE_MMX) || defined(HAVE_SSE) #include "x86/mdct.h" #endif #ifdef HAVE_ALTIVEC #include "ppc/mdct.h" #endif #define ONE FCONST(1.0) #define TWO FCONST(2.0) #define AFT_PI3_8 FCONST(0.38268343236508977175) #define AFT_PI2_8 FCONST(0.70710678118654752441) #define AFT_PI1_8 FCONST(0.92387953251128675613) struct A52Context; struct A52ThreadContext; typedef struct MDCTContext { void (*mdct)(struct A52ThreadContext *ctx, FLOAT *out, FLOAT *in); void (*mdct_bitreverse)(struct MDCTContext *mdct, FLOAT *x); void (*mdct_butterfly_generic)(struct MDCTContext *mdct, FLOAT *x, int points, int trigint); void (*mdct_butterfly_first)(FLOAT *trig, FLOAT *x, int points); void (*mdct_butterfly_32)(FLOAT *x); FLOAT *trig; #ifndef CONFIG_DOUBLE #ifdef HAVE_SSE FLOAT *trig_bitreverse; FLOAT *trig_forward; FLOAT *trig_butterfly_first; FLOAT *trig_butterfly_generic8; FLOAT *trig_butterfly_generic16; FLOAT *trig_butterfly_generic32; FLOAT *trig_butterfly_generic64; #endif #endif /* CONFIG_DOUBLE */ int *bitrev; FLOAT scale; int n; int log2n; } MDCTContext; typedef struct { MDCTContext *mdct; FLOAT *buffer; FLOAT *buffer1; } MDCTThreadContext; extern void mdct_ctx_init(MDCTContext *mdct, int n); extern void mdct_init(struct A52Context *ctx); extern void mdct_close(struct A52Context *ctx); extern void mdct_thread_init(struct A52ThreadContext *tctx); extern void mdct_thread_close(struct A52ThreadContext *tctx); #endif /* MDCT_H */ aften/libaften/mem.h000066400000000000000000000032311132016273200146620ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * Copyright (c) 2007 Justin Ruggles * Copyright (c) 2007 Prakash Punnoor * * Uses a modified version of memalign hack from FFmpeg * Copyright (c) 2002 Fabrice Bellard. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file mem.h * Memory-related functions */ #ifndef MEM_H #define MEM_H #include "common.h" #ifdef HAVE_POSIX_MEMALIGN static inline void * aligned_malloc(size_t size) { void *mem; if (posix_memalign(&mem, 16, size)) return NULL; return mem; } #define aligned_free(X) free(X) #else static inline void* aligned_malloc(long size) { char *mem; long diff; mem = malloc(size+32); if (!mem) return mem; diff = ((long)mem & 15) - 32; mem -= diff; ((int *)mem)[-1] = (int)diff; return mem; } static inline void aligned_free(void *ptr) { if (ptr) free((char*)ptr + ((int*)ptr)[-1]); } #endif /* HAVE_POSIX_MEMALIGN */ #endif /* MEM_H */ aften/libaften/ppc/000077500000000000000000000000001132016273200145165ustar00rootroot00000000000000aften/libaften/ppc/altivec_common.h000066400000000000000000000044751132016273200177000ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * Copyright (c) 2007, David Conrad * Copyright (c) 2006, Ryan C. Gordon * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef ALTIVEC_COMMON_H #define ALTIVEC_COMMON_H typedef vector unsigned char vec_u8_t; typedef vector signed char vec_s8_t; typedef vector unsigned short vec_u16_t; typedef vector signed short vec_s16_t; typedef vector unsigned int vec_u32_t; typedef vector signed int vec_s32_t; #if defined( __APPLE_CC__ ) && defined( __APPLE_ALTIVEC__ ) /* apple */ #define VEC_U32(a,b,c,d) (vec_u32_t) (a, b, c, d) #define VEC_FLOAT(a,b,c,d) (vector float) (a, b, c, d) #define VPERMUTE4(a,b,c,d) (vec_u8_t) \ ( (a*4)+0, (a*4)+1, (a*4)+2, (a*4)+3, \ (b*4)+0, (b*4)+1, (b*4)+2, (b*4)+3, \ (c*4)+0, (c*4)+1, (c*4)+2, (c*4)+3, \ (d*4)+0, (d*4)+1, (d*4)+2, (d*4)+3 ) #else /* gnu */ #define VEC_U32(a,b,c,d) {a, b, c, d} #define VEC_FLOAT(a,b,c,d) {a, b, c, d} #define VPERMUTE4(a,b,c,d) \ { (a*4)+0, (a*4)+1, (a*4)+2, (a*4)+3, \ (b*4)+0, (b*4)+1, (b*4)+2, (b*4)+3, \ (c*4)+0, (c*4)+1, (c*4)+2, (c*4)+3, \ (d*4)+0, (d*4)+1, (d*4)+2, (d*4)+3 } #endif static inline vector float vec_ld_float(const float *a) { switch ((int)a & 0xc) { case 4: return vec_splat(vec_lde(0, a), 1); case 8: return vec_splat(vec_lde(0, a), 2); case 12: return vec_splat(vec_lde(0, a), 3); } return vec_splat(vec_lde(0, a), 0); } #endif aften/libaften/ppc/cpu_caps.c000066400000000000000000000050141132016273200164570ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * Copyright (c) 2006, David Conrad * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "common.h" #include "ppc/cpu_caps.h" int ppc_cpu_caps_altivec = 0; // Altivec detection from // http://developer.apple.com/hardwaredrivers/ve/g3_compatibility.html #ifdef SYS_DARWIN #include #else #include #include volatile int g_is_altivec_present = -1L; static sigjmp_buf g_env; void sig_ill_handler(int sig) { //Set our flag to 0 to indicate AltiVec is illegal g_is_altivec_present = 0; //long jump back to safety siglongjmp(g_env, 0); } #endif #ifdef SYS_DARWIN void cpu_caps_detect(void) { int sels[2] = { CTL_HW, HW_VECTORUNIT }; int v_type = 0; //0 == scalar only size_t len = sizeof(v_type); int err = sysctl(sels, 2, &v_type, &len, NULL, 0); ppc_cpu_caps_altivec = err == 0 && v_type != 0; } #else void cpu_caps_detect(void) { if (g_is_altivec_present == -1L) { sig_t oldhandler; sigset_t signame; struct sigaction sa_new, sa_old; //Set AltiVec to ON g_is_altivec_present = 1; //Set up the signal mask sigemptyset(&signame); sigaddset(&signame, SIGILL); //Set up the signal handler sa_new.sa_handler = sig_ill_handler; sa_new.sa_mask = signame; sa_new.sa_flags = 0; //Install the signal handler sigaction(SIGILL, &sa_new, &sa_old); //Attempt to use AltiVec if(!sigsetjmp(g_env, 0)) { asm volatile ( "vor 0, 0, 0" ); } //Restore the old signal handler sigaction(SIGILL, &sa_old, &sa_new); } ppc_cpu_caps_altivec = g_is_altivec_present; } #endif void apply_simd_restrictions(AftenSimdInstructions *simd_instructions) { ppc_cpu_caps_altivec &= simd_instructions->altivec; } aften/libaften/ppc/cpu_caps.h000066400000000000000000000021551132016273200164670ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * Copyright (c) 2006 David Conrad * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef PPC_CPU_CAPS_H #define PPC_CPU_CAPS_H #include "common.h" #include "aften-types.h" extern int ppc_cpu_caps_altivec; void cpu_caps_detect(void); void apply_simd_restrictions(AftenSimdInstructions *simd_instructions); static inline int cpu_caps_have_altivec(void) { return ppc_cpu_caps_altivec; } #endif aften/libaften/ppc/mdct.h000066400000000000000000000036351132016273200156250ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * * Copyright (c) 2007, David Conrad * Copyright (c) 2006, Ryan C. Gordon * Copyright (c) 2002, 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. */ /** * @file ppc/mdct.h * PPC MDCT header */ #ifndef PPC_MDCT_H #define PPC_MDCT_H #include "common.h" struct A52Context; struct A52ThreadContext; #ifndef CONFIG_DOUBLE #ifdef HAVE_ALTIVEC extern void mdct_init_altivec(struct A52Context *ctx); #endif #endif #endif /* PPC_MDCT_H */ aften/libaften/ppc/mdct_altivec.c000066400000000000000000000502461132016273200173270ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * * Copyright (c) 2007, David Conrad * Copyright (c) 2006, Ryan C. Gordon * Copyright (c) 2002, 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. */ /** * @file ppc/mdct_altivec.c * MDCT, optimized for the AltiVec instruction set */ #include #include "a52enc.h" #include "altivec_common.h" #include "mem.h" // sign change constants static const vec_u32_t vPNNP = VEC_U32 (0x00000000, 0x80000000, 0x80000000, 0x00000000); static const vec_u32_t vPNPN = VEC_U32 (0x00000000, 0x80000000, 0x00000000, 0x80000000); static const vec_u32_t vNNNN = VEC_U32 (0x80000000, 0x80000000, 0x80000000, 0x80000000); static inline void mdct_butterfly_8_altivec(FLOAT *x) { vector float x0to3, x4to7, vPlus, vMinus, v1, v2, v3, v4; vec_u8_t perm0101 = VPERMUTE4(0, 1, 0, 1); vec_u32_t vNNPP = vec_sld(vPNNP, vPNNP, 4); x0to3 = vec_ld(0x00, x); x4to7 = vec_ld(0x10, x); vPlus = vec_add(x4to7, x0to3); vMinus = vec_sub(x4to7, x0to3); v2 = vec_perm(vMinus, vMinus, perm0101); v2 = vec_sld(v2, v2, 4); v4 = vec_perm(vPlus, vPlus, perm0101); vMinus = vec_sld(vMinus, vMinus, 8); vPlus = vec_sld(vPlus, vPlus, 8); v1 = vec_perm(vMinus, vMinus, perm0101); v3 = vec_perm(vPlus, vPlus, perm0101); v2 = vec_xor(v2, (vector float)vPNNP); v4 = vec_xor(v4, (vector float)vNNPP); x0to3 = vec_add(v1, v2); x4to7 = vec_add(v3, v4); vec_st(x0to3, 0x00, x); vec_st(x4to7, 0x10, x); } static inline void mdct_butterfly_16_altivec(FLOAT *x) { vec_u8_t perm1036 = VPERMUTE4(1, 0, 3, 6); vec_u8_t perm5472 = VPERMUTE4(5, 4, 7, 2); vector float zero = (vector float) vec_splat_u32(0); vector float pi2_8 = VEC_FLOAT(AFT_PI2_8, AFT_PI2_8, AFT_PI2_8, AFT_PI2_8); vector float x0to3, x4to7, x8to11, x12to15; vector float v1, v2, v3, v4, v5; x0to3 = vec_ld(0x00, x); x4to7 = vec_ld(0x10, x); x8to11 = vec_ld(0x20, x); x12to15 = vec_ld(0x30, x); v1 = vec_perm(x0to3, x8to11, perm1036); v2 = vec_perm(x0to3, x8to11, perm5472); v1 = vec_sub(v1, v2); v2 = vec_sub(x12to15, x4to7); v3 = vec_mergeh(v1, v1); v4 = vec_mergeh(v2, v2); v5 = vec_sld(v3, v3, 8); v5 = vec_sld(v5, v4, 8); v4 = vec_sld(v4, v4, 8); v3 = vec_sld(v3, v4, 8); v3 = vec_xor(v3, (vector float)vPNNP); v3 = vec_add(v5, v3); v3 = vec_madd(v3, pi2_8, zero); v1 = vec_sld(v1, v1, 8); v2 = vec_sld(v2, v2, 8); v4 = vec_sld(v3, v3, 8); v4 = vec_sld(v4, v1, 8); v5 = vec_sld(v3, v2, 8); v1 = vec_add(x8to11, x0to3); v2 = vec_add(x12to15, x4to7); vec_st(v4, 0x00, x); vec_st(v5, 0x10, x); vec_st(v1, 0x20, x); vec_st(v2, 0x30, x); mdct_butterfly_8_altivec(x); mdct_butterfly_8_altivec(x+8); } static inline void mdct_butterfly_32_altivec(FLOAT *x) { vec_u8_t perm0022 = VPERMUTE4(0, 0, 2, 2); vec_u8_t perm1405 = VPERMUTE4(1, 4, 0, 5); vector float zero = (vector float) vec_splat_u32(0); vector float cpi = VEC_FLOAT(AFT_PI2_8, AFT_PI2_8, AFT_PI1_8, AFT_PI3_8); vec_u32_t vNPNP = vec_sld(vPNPN, vPNPN, 4); vector float x0to3, x4to7, x8to11, x12to15, x16to19, x20to23, x24to27, x28to31; vector float pi3122, pi1322, pi1313, pi3131; vector float v1, v2, v3, v4; pi1322 = vec_sld(cpi, cpi, 8); pi1313 = vec_sld(cpi, pi1322, 8); pi3131 = vec_sld(pi1313, pi1313, 4); pi3122 = vec_sld(pi3131, cpi, 8); x0to3 = vec_ld(0x00, x); x4to7 = vec_ld(0x10, x); x8to11 = vec_ld(0x20, x); x12to15 = vec_ld(0x30, x); x16to19 = vec_ld(0x40, x); x20to23 = vec_ld(0x50, x); x24to27 = vec_ld(0x60, x); x28to31 = vec_ld(0x70, x); v1 = vec_sub(x0to3, x16to19); v2 = vec_perm(v1, v1, perm0022); v1 = vec_sld(v1, v1, 4); v1 = vec_perm(v1, v1, perm0022); v2 = vec_madd(v2, pi1322, zero); v2 = vec_xor(v2, (vector float)vPNPN); v1 = vec_madd(v1, pi3122, v2); vec_st(v1, 0x00, x); v1 = vec_sub(x24to27, x8to11); v2 = vec_perm(v1, v1, perm0022); v1 = vec_sld(v1, v1, 4); v1 = vec_perm(v1, v1, perm0022); v2 = vec_madd(v2, pi3122, zero); v1 = vec_xor(v1, (vector float)vNPNP); v1 = vec_madd(v1, pi1322, v2); vec_st(v1, 0x20, x); v1 = vec_sub(x4to7, x20to23); v2 = vec_sub(x28to31, x12to15); v3 = vec_perm(v1, v2, perm1405); v4 = vec_mergel(v3, v3); v3 = vec_mergeh(v3, v3); v4 = vec_madd(v4, pi3131, zero); v3 = vec_madd(v3, pi1313, zero); v4 = vec_xor(v4, (vector float)vPNNP); v3 = vec_add(v3, v4); v2 = vec_sld(v2, v2, 8); v4 = vec_sld(v3, v2, 8); vec_st(v4, 0x30, x); v1 = vec_xor(v1, (vector float)vPNNP); v2 = vec_sld(v1, v1, 8); v1 = vec_sld(v1, v2, 12); v3 = vec_sld(v3, v3, 8); v1 = vec_sld(v3, v1, 8); vec_st(v1, 0x10, x); x16to19 = vec_add(x16to19, x0to3); x20to23 = vec_add(x20to23, x4to7); x24to27 = vec_add(x24to27, x8to11); x28to31 = vec_add(x28to31, x12to15); vec_st(x16to19, 0x40, x); vec_st(x20to23, 0x50, x); vec_st(x24to27, 0x60, x); vec_st(x28to31, 0x70, x); mdct_butterfly_16_altivec(x); mdct_butterfly_16_altivec(x+16); } /* in place N point first stage butterfly */ /* XXX: equivalent to mdct_butterfly_generic w/ trigint = 4 */ static inline void mdct_butterfly_first_altivec(FLOAT *trig, FLOAT *x, int points) { vec_u8_t perm5410 = VPERMUTE4(5, 4, 1, 0); vec_u8_t perm4501 = VPERMUTE4(4, 5, 0, 1); vec_u8_t perm0022 = VPERMUTE4(0, 0, 2, 2); vec_u8_t perm1133 = vec_add(perm0022, vec_splat_u8(4)); vector float zero = (vector float) vec_splat_u32(0); vector float vTa, vTb, vTc, vTd; vector float x1a, x1b, x2a, x2b; vector float v1, v2, v3, v4, v5, v6, v7, v8; FLOAT *x1 = x + points - 8; FLOAT *x2 = x + (points>>1) - 8; do { x1a = vec_ld(0x00, x1); x1b = vec_ld(0x10, x1); x2a = vec_ld(0x00, x2); x2b = vec_ld(0x10, x2); vTa = vec_ld(0x00, trig); vTb = vec_ld(0x10, trig); vTc = vec_ld(0x20, trig); vTd = vec_ld(0x30, trig); v5 = vec_sub(x1a, x2a); v6 = vec_sub(x1b, x2b); v1 = vec_perm(v5, v5, perm1133); v2 = vec_perm(v6, v6, perm1133); v3 = vec_perm(v5, v5, perm0022); v4 = vec_perm(v6, v6, perm0022); v5 = vec_perm(vTc, vTd, perm5410); v6 = vec_perm(vTa, vTb, perm5410); v7 = vec_perm(vTc, vTd, perm4501); v8 = vec_perm(vTa, vTb, perm4501); v3 = vec_xor(v3, (vector float)vPNPN); v4 = vec_xor(v4, (vector float)vPNPN); v1 = vec_madd(v1, v5, zero); v2 = vec_madd(v2, v6, zero); v3 = vec_madd(v3, v7, v1); v4 = vec_madd(v4, v8, v2); v1 = vec_add(x1a, x2a); v2 = vec_add(x1b, x2b); vec_st(v1, 0x00, x1); vec_st(v2, 0x10, x1); vec_st(v3, 0x00, x2); vec_st(v4, 0x10, x2); x1 -= 8; x2 -= 8; trig += 16; } while (x2 >= x); } static inline void mdct_butterfly_generic_altivec(float *trig, float *x, int points, int trigint) { vec_u8_t perm5410 = VPERMUTE4(5, 4, 1, 0); vec_u8_t perm4501 = VPERMUTE4(4, 5, 0, 1); vec_u8_t perm0022 = VPERMUTE4(0, 0, 2, 2); vec_u8_t perm1133 = vec_add(perm0022, vec_splat_u8(4)); vector float zero = (vector float) vec_splat_u32(0); vector float vTa, vTb, vTc, vTd; vector float x1a, x1b, x2a, x2b; vector float v1, v2, v3, v4, v5, v6, v7, v8; FLOAT *x1 = x + points - 8; FLOAT *x2 = x + (points>>1) - 8; do { x1a = vec_ld(0x00, x1); x1b = vec_ld(0x10, x1); x2a = vec_ld(0x00, x2); x2b = vec_ld(0x10, x2); vTa = vec_ld(0, trig); trig += trigint; vTb = vec_ld(0, trig); trig += trigint; vTc = vec_ld(0, trig); trig += trigint; vTd = vec_ld(0, trig); trig += trigint; v5 = vec_sub(x1a, x2a); v6 = vec_sub(x1b, x2b); v1 = vec_perm(v5, v5, perm1133); v2 = vec_perm(v6, v6, perm1133); v3 = vec_perm(v5, v5, perm0022); v4 = vec_perm(v6, v6, perm0022); v5 = vec_perm(vTc, vTd, perm5410); v6 = vec_perm(vTa, vTb, perm5410); v7 = vec_perm(vTc, vTd, perm4501); v8 = vec_perm(vTa, vTb, perm4501); v3 = vec_xor(v3, (vector float)vPNPN); v4 = vec_xor(v4, (vector float)vPNPN); v1 = vec_madd(v1, v5, zero); v2 = vec_madd(v2, v6, zero); v3 = vec_madd(v3, v7, v1); v4 = vec_madd(v4, v8, v2); v1 = vec_add(x1a, x2a); v2 = vec_add(x1b, x2b); vec_st(v1, 0x00, x1); vec_st(v2, 0x10, x1); vec_st(v3, 0x00, x2); vec_st(v4, 0x10, x2); x1 -= 8; x2 -= 8; } while (x2>=x); } static inline void mdct_butterflies_altivec(MDCTContext *mdct, FLOAT *x, int points) { FLOAT *trig = mdct->trig; int stages = mdct->log2n-5; int i, j; if (--stages > 0) { mdct_butterfly_first_altivec(trig,x,points); //mdct_butterfly_generic_altivec(trig,x,points,4); } for (i = 1; --stages > 0; i++) { for (j = 0; j < (1<>i)*j, points>>i, 4<n; int *bit0 = mdct->bitrev; int *bit1 = mdct->bitrev + mdct->n/4; FLOAT *w0 = x; FLOAT *w1 = x = w0+(n>>1); FLOAT *w2 = w0+(n>>2); FLOAT *w3 = w2; FLOAT *trig0 = mdct->trig+n; FLOAT *trig1 = trig0+(n>>2); vector float vx0, vx1, vx2, vx3, v0, v1, v2, v3, v4, v5; vector float vPlus0, vPlus1, vMinus0, vMinus1; vector float vtrig0, vtrig0swap, vtrig1, vtrig1swap; vec_u8_t perm0145 = VPERMUTE4(0, 1, 4, 5); vec_u8_t perm2301 = VPERMUTE4(2, 3, 0, 1); vec_u8_t perm1032 = VPERMUTE4(1, 0, 3, 2); vec_u8_t perm4400 = VPERMUTE4(4, 4, 0, 0); vec_u8_t perm1414 = VPERMUTE4(1, 4, 1, 4); vec_u8_t perm2367 = vec_add(perm0145, vec_splat_u8(8)); vec_u8_t perm5511 = vec_add(perm4400, vec_splat_u8(4)); vec_u8_t perm3636 = vec_add(perm1414, vec_splat_u8(8)); vec_u8_t perm2266, perm3377; vector float point5 = VEC_FLOAT(0.5f, 0.5f, 0.5f, 0.5f); vector float zero = (vector float) vec_splat_u32(0); vec_u32_t vNPNP = vec_sld(vPNPN, vPNPN, 4); perm2266 = vec_add(perm5511, vec_splat_u8(4)); perm2266 = vec_sld(perm2266, perm2266, 8); perm3377 = vec_add(perm2266, vec_splat_u8(4)); // unrolled by 2 from C MDCT, so that we can operate on all 4 elements // loaded at once rather than 2 (and working on the other 2 later), // and so we don't have to worry about unaligned loads do { w1 -= 4; w2 -= 4; trig1 -= 4; bit1 -= 4; vx0 = vec_ld(0, x+bit0[1]); vx1 = vec_ld(0, x+bit0[3]); vx2 = vec_ld(0, x+bit1[1]); vx3 = vec_ld(0, x+bit1[3]); vtrig0 = vec_ld(0, trig0); vtrig1 = vec_ld(0, trig1); vtrig0swap = vec_perm(vtrig0, vtrig0, perm1032); vtrig1swap = vec_perm(vtrig1, vtrig1, perm1032); v0 = vec_perm(vx0, vx3, perm2367); v1 = vec_perm(vx3, vx0, perm0145); v2 = vec_perm(vx1, vx2, perm2367); v3 = vec_perm(vx2, vx1, perm0145); vPlus0 = vec_add(v0, v1); vMinus0 = vec_sub(v0, v1); vPlus1 = vec_add(v2, v3); vMinus1 = vec_sub(v2, v3); v0 = vec_perm(vPlus0, vPlus1, perm2266); v1 = vec_perm(vMinus0, vMinus1, perm3377); v1 = vec_xor(v1, (vector float) vPNPN); v1 = vec_madd(v1, vtrig0swap, zero); v0 = vec_madd(v0, vtrig0, v1); v1 = vec_perm(v0, v0, perm2301); v1 = vec_xor(v1, (vector float) vNPNP); v4 = vec_perm(vPlus0, vMinus0, perm3636); v5 = vec_perm(vPlus1, vMinus1, perm3636); v2 = vec_perm(v4, v5, perm0145); v3 = vec_perm(v5, v4, perm0145); v2 = vec_madd(v2, point5, v0); v3 = vec_xor(v3, (vector float) vPNPN); v3 = vec_madd(v3, point5, v1); vec_st(v2, 0, w0); vec_st(v3, 0, w1); v0 = vec_perm(vPlus0, vPlus1, perm4400); v1 = vec_perm(vMinus0, vMinus1, perm5511); v1 = vec_xor(v1, (vector float) vPNPN); v1 = vec_madd(v1, vtrig1swap, zero); v0 = vec_madd(v0, vtrig1, v1); v1 = vec_perm(v0, v0, perm2301); v1 = vec_xor(v1, (vector float) vNPNP); v4 = vec_perm(vPlus1, vMinus1, perm1414); v5 = vec_perm(vPlus0, vMinus0, perm1414); v2 = vec_perm(v4, v5, perm0145); v3 = vec_perm(v5, v4, perm0145); v2 = vec_madd(v2, point5, v0); v3 = vec_xor(v3, (vector float) vPNPN); v3 = vec_madd(v3, point5, v1); vec_st(v2, 0, w2); vec_st(v3, 0, w3); bit0 += 4; trig0 += 4; w0 += 4; w3 += 4; } while (w2 > w0); } static void mdct_altivec(MDCTThreadContext *tmdct, FLOAT *out, FLOAT *in) { MDCTContext *mdct = tmdct->mdct; int n = mdct->n; int n2 = n>>1; int n4 = n>>2; int n8 = n>>3; FLOAT *w = tmdct->buffer; FLOAT *w2 = w+n2; FLOAT *x0 = in+n2+n4; FLOAT *x1 = x0; FLOAT *trig = mdct->trig + n2; int i; vec_u8_t perm3210 = VPERMUTE4(3, 2, 1, 0); vec_u8_t perm2301 = VPERMUTE4(2, 3, 0, 1); vec_u8_t perm0022 = VPERMUTE4(0, 0, 2, 2); vec_u8_t perm0246 = VPERMUTE4(0, 2, 4, 6); vec_u8_t perm6420 = VPERMUTE4(6, 4, 2, 0); vec_u8_t perm1357 = vec_add(perm0246, vec_splat_u8(4)); vec_u8_t perm7531 = vec_add(perm6420, vec_splat_u8(4)); vector unsigned char perm1133 = vec_add(perm0022, vec_splat_u8(4)); vec_u8_t perm3175 = vec_sld(perm7531, perm7531, 8); vec_u8_t perm4602; vector float zero = (vector float) vec_splat_u32(0); vector float x0_0to3, x0_4to7, x1_0to3, x1_4to7, w0to3, w4to7; vector float trig0to3, trig4to7; vector float v0, v1, v2, v3, v4; vector float vScale = vec_ld_float(&mdct->scale); perm4602 = vec_perm(perm6420, perm6420, perm3210); perm4602 = vec_perm(perm4602, perm4602, perm2301); for (i = 0; i < n8; i += 4) { x0 -= 8; trig -= 4; x0_0to3 = vec_ld(0x00, x0); x0_4to7 = vec_ld(0x10, x0); x1_0to3 = vec_ld(0x00, x1); x1_4to7 = vec_ld(0x10, x1); trig0to3 = vec_ld(0, trig); v0 = vec_perm(x0_0to3, x0_4to7, perm4602); v1 = vec_perm(x1_0to3, x1_4to7, perm3175); v0 = vec_add(v0, v1); v1 = vec_perm(trig0to3, trig0to3, perm3210); v2 = vec_perm(trig0to3, trig0to3, perm2301); v2 = vec_xor(v2, (vector float) vPNPN); v3 = vec_perm(v0, v0, perm0022); v3 = vec_madd(v3, v1, zero); v4 = vec_perm(v0, v0, perm1133); v0 = vec_madd(v4, v2, v3); vec_st(v0, 0, &w2[i]); x1 += 8; } x1 = in; for (; i < n2-n8; i += 4) { x0 -= 8; trig -= 4; x0_0to3 = vec_ld(0x00, x0); x0_4to7 = vec_ld(0x10, x0); x1_0to3 = vec_ld(0x00, x1); x1_4to7 = vec_ld(0x10, x1); trig0to3 = vec_ld(0, trig); v0 = vec_perm(x0_0to3, x0_4to7, perm4602); v1 = vec_perm(x1_0to3, x1_4to7, perm3175); v0 = vec_sub(v0, v1); v1 = vec_perm(trig0to3, trig0to3, perm3210); v2 = vec_perm(trig0to3, trig0to3, perm2301); v2 = vec_xor(v2, (vector float) vPNPN); v3 = vec_perm(v0, v0, perm0022); v3 = vec_madd(v3, v1, zero); v4 = vec_perm(v0, v0, perm1133); v0 = vec_madd(v4, v2, v3); vec_st(v0, 0, &w2[i]); x1 += 8; } x0 = in+n; for (; i < n2; i += 4) { trig -= 4; x0 -= 8; x0_0to3 = vec_ld(0x00, x0); x0_4to7 = vec_ld(0x10, x0); x1_0to3 = vec_ld(0x00, x1); x1_4to7 = vec_ld(0x10, x1); trig0to3 = vec_ld(0, trig); v0 = vec_perm(x0_0to3, x0_4to7, perm4602); v1 = vec_perm(x1_0to3, x1_4to7, perm3175); v0 = vec_xor(v0, (vector float) vNNNN); v0 = vec_sub(v0, v1); v1 = vec_perm(trig0to3, trig0to3, perm3210); v2 = vec_perm(trig0to3, trig0to3, perm2301); v2 = vec_xor(v2, (vector float) vPNPN); v3 = vec_perm(v0, v0, perm0022); v3 = vec_madd(v3, v1, zero); v4 = vec_perm(v0, v0, perm1133); v0 = vec_madd(v4, v2, v3); vec_st(v0, 0, &w2[i]); x1 += 8; } mdct_butterflies_altivec(mdct, w2, n2); mdct_bitreverse_altivec(mdct, w); trig = mdct->trig+n2; x0 = out+n2; for (i = 0; i < n4; i += 4) { x0-=4; w0to3 = vec_ld(0x00, w); w4to7 = vec_ld(0x10, w); trig0to3 = vec_ld(0x00, trig); trig4to7 = vec_ld(0x10, trig); v0 = vec_madd(w0to3, trig0to3, zero); v1 = vec_madd(w4to7, trig4to7, zero); v2 = vec_perm(v0, v1, perm0246); v3 = vec_perm(v0, v1, perm1357); v0 = vec_add(v2, v3); v0 = vec_madd(v0, vScale, zero); v1 = vec_perm(w0to3, w4to7, perm6420); v2 = vec_perm(w0to3, w4to7, perm7531); v3 = vec_perm(trig0to3, trig4to7, perm7531); v4 = vec_perm(trig0to3, trig4to7, perm6420); v1 = vec_madd(v1, v3, zero); v2 = vec_madd(v2, v4, zero); v1 = vec_sub(v1, v2); v1 = vec_madd(v1, vScale, zero); vec_st(v0, 0, &out[i]); vec_st(v1, 0, x0); w += 8; trig += 8; } } static void mdct_512_altivec(A52ThreadContext *tctx, FLOAT *out, FLOAT *in) { mdct_altivec(&tctx->mdct_tctx_512, out, in); } static void mdct_256_altivec(A52ThreadContext *tctx, FLOAT *out, FLOAT *in) { FLOAT *coef_a = in; FLOAT *coef_b = in+128; FLOAT *xx = tctx->mdct_tctx_256.buffer1; int i; vector float v0, v1, v_coef_a, v_coef_b; memcpy(xx, in+64, 192 * sizeof(FLOAT)); for (i = 0; i < 64; i += 4) { v0 = vec_ld(0, in+i); v0 = vec_xor(v0, (vector float) vNNNN); vec_st(v0, 0, xx+i+192); } mdct_altivec(&tctx->mdct_tctx_256, coef_a, xx); for (i = 0; i < 64; i += 4) { v0 = vec_ld(0, in+i+256+192); v0 = vec_xor(v0, (vector float) vNNNN); vec_st(v0, 0, xx+i); } memcpy(xx+64, in+256, 128 * sizeof(FLOAT)); for (i = 0; i < 64; i += 4) { v0 = vec_ld(0, in+i+256+128); v0 = vec_xor(v0, (vector float) vNNNN); vec_st(v0, 0, xx+i+192); } mdct_altivec(&tctx->mdct_tctx_256, coef_b, xx); for (i = 0; i < 128; i += 4) { v_coef_a = vec_ld(0, coef_a+i); v_coef_b = vec_ld(0, coef_b+i); v0 = vec_mergeh(v_coef_a, v_coef_b); v1 = vec_mergel(v_coef_a, v_coef_b); vec_st(v0, 0, out+2*i); vec_st(v1, 0, out+2*i+4); } } void mdct_init_altivec(A52Context *ctx) { mdct_ctx_init(&ctx->mdct_ctx_512, 512); mdct_ctx_init(&ctx->mdct_ctx_256, 256); ctx->mdct_ctx_512.mdct = mdct_512_altivec; ctx->mdct_ctx_256.mdct = mdct_256_altivec; } aften/libaften/threading.h000066400000000000000000000137101132016273200160540ustar00rootroot00000000000000/******************************************************************************** * Copyright (C) 2005-2007 by Prakash Punnoor * * prakash@punnoor.de * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2 of the License * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with this library; if not, write to the Free Software * * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * ********************************************************************************/ #ifndef THREADING_H #define THREADING_H #include "common.h" typedef enum { START, WORK, END, ABORT } ThreadState; #ifdef HAVE_POSIX_THREADS #include typedef pthread_t THREAD; typedef pthread_mutex_t MUTEX; typedef pthread_cond_t COND; typedef struct A52GlobalThreadSync { int current_thread_num; int threads_to_abort; int threads_running; volatile int samples_thread_num; MUTEX samples_mutex; } A52GlobalThreadSync; typedef struct A52ThreadSync { THREAD thread; MUTEX enter_mutex; MUTEX confirm_mutex; COND enter_cond; COND confirm_cond; COND samples_cond; COND* next_samples_cond; } A52ThreadSync; #define thread_create(threadid, threadfunc, threadparam) \ pthread_create(threadid, NULL, (void *(*) (void *))threadfunc, threadparam) #define thread_join(x) pthread_join(x, NULL) #define posix_mutex_init(x) pthread_mutex_init(x, NULL) #define posix_mutex_destroy(x) pthread_mutex_destroy(x) #define posix_mutex_lock(x) pthread_mutex_lock(x) #define posix_mutex_unlock(x) pthread_mutex_unlock(x) #define posix_cond_init(x) pthread_cond_init(x, NULL) #define posix_cond_destroy(x) pthread_cond_destroy(x) #define posix_cond_wait(cond, mutex) pthread_cond_wait(cond, mutex) #define posix_cond_signal(x) pthread_cond_signal(x) #define posix_cond_broadcast(x) pthread_cond_broadcast(x) #ifdef HAVE_GET_NPROCS #include static inline int get_ncpus() { return get_nprocs(); } #elif defined(SYS_DARWIN) #undef _POSIX_C_SOURCE #include static inline int get_ncpus() { int mib[2] = { CTL_HW, HW_NCPU }; int numCPUs; size_t len = sizeof(numCPUs); return sysctl(mib, 2, &numCPUs, &len, NULL, 0) ? 1 : numCPUs; } #else static inline int get_ncpus() { return NUM_THREADS; } #endif #else /* HAVE_POSIX_THREADS */ #ifdef HAVE_WINDOWS_THREADS #include typedef HANDLE THREAD; typedef HANDLE EVENT; typedef CRITICAL_SECTION CS; typedef struct A52GlobalThreadSync { int current_thread_num; int threads_to_abort; int threads_running; volatile int samples_thread_num; CS samples_cs; } A52GlobalThreadSync; typedef struct A52ThreadSync { THREAD thread; EVENT ready_event; EVENT enter_event; EVENT samples_event; EVENT* next_samples_event; } A52ThreadSync; static inline void thread_create(HANDLE *thread, int (*threadfunc)(void*), LPVOID threadparam) { DWORD thread_id; *thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)threadfunc, threadparam, 0, &thread_id); } static inline void thread_join(HANDLE thread) { WaitForSingleObject(thread, INFINITE); CloseHandle(thread); } static inline void windows_event_init(EVENT *event) { *event = CreateEvent(NULL, FALSE, FALSE, NULL); } static inline void windows_event_destroy(EVENT *event) { CloseHandle(*event); } static inline void windows_event_set(EVENT *event) { SetEvent(*event); } static inline void windows_event_reset(EVENT *event) { ResetEvent(*event); } static inline void windows_event_wait(EVENT *event) { WaitForSingleObject(*event, INFINITE); } static inline void windows_cs_init(CS *cs) { InitializeCriticalSection(cs); } static inline void windows_cs_destroy(CS *cs) { DeleteCriticalSection(cs); } static inline void windows_cs_enter(CS *cs) { EnterCriticalSection(cs); } static inline void windows_cs_leave(CS *cs) { LeaveCriticalSection(cs); } static inline int get_ncpus() { SYSTEM_INFO sys_info; GetSystemInfo(&sys_info); return sys_info.dwNumberOfProcessors; } #else /* HAVE_WINDOWS_THREADS */ #define NO_THREADS static inline int get_ncpus() { return 1; } #define thread_create(X, Y, Z) #define thread_join(X) #endif /* HAVE_WINDOWS_THREADS */ #endif /* HAVE_POSIX_THREADS */ #ifndef HAVE_POSIX_THREADS #define posix_mutex_init(x) #define posix_mutex_destroy(x) #define posix_mutex_lock(x) #define posix_mutex_unlock(x) #define posix_cond_init(x) #define posix_cond_destroy(x) #define posix_cond_wait(cond, mutex) #define posix_cond_signal(x) #define posix_cond_broadcast(x) #endif /* HAVE_POSIX_THREADS */ #ifndef HAVE_WINDOWS_THREADS #define windows_event_init(x) #define windows_event_destroy(x) #define windows_event_set(x) #define windows_event_reset(x) #define windows_event_wait(x) #define windows_cs_init(x) #define windows_cs_destroy(x) #define windows_cs_enter(x) #define windows_cs_leave(x) #endif /* HAVE_WINDOWS_THREADS */ #endif /* THREADING_H */ aften/libaften/util.c000066400000000000000000000171511132016273200150620ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * Copyright (c) 2006 Justin Ruggles * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file util.c * libaften utility functions */ #include "aften.h" #include "a52.h" static const int8_t ch_to_acmod[6] = { A52_ACMOD_MONO, A52_ACMOD_STEREO, A52_ACMOD_3_0, A52_ACMOD_2_2, A52_ACMOD_3_2, A52_ACMOD_3_2 }; const uint8_t log2tab[256] = { 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 }; static int chmask_get_num_channels(unsigned int chmask) { int count; for (count = 0; chmask; count++) chmask &= chmask-1; // unset lowest set bit return count; } /** * Determines the proper A/52 acmod and lfe parameters based on the * number of channels and the WAVE_FORMAT_EXTENSIBLE channel mask. If the * chmask value has the high bit set to 1 (e.g. 0xFFFFFFFF), then the default * plain WAVE channel selection is assumed. * On error, the function returns -1. On success, the acmod and lfe params are * set to appropriate values and the function returns 0. */ int aften_wav_channels_to_acmod(int ch, unsigned int chmask, int *acmod, int *lfe) { int tmp_lfe, tmp_acmod; // check for valid number of channels if (ch < 1 || ch > A52_MAX_CHANNELS) { fprintf(stderr, "Unsupported # of channels passed to aften_wav_chmask_to_acmod\n"); return -1; } chmask &= 0x7FFFFFFF; if (!chmask) { // set values for plain WAVE format or unknown configuration tmp_lfe = (ch == 6); if (tmp_lfe) ch--; tmp_acmod = ch_to_acmod[ch-1]; } else { // check number of channel bits set in chmask and compare to ch if (chmask_get_num_channels(chmask) != ch) { fprintf(stderr, "channel mask and number of channels do not match\n"); return -1; } // read chmask value for LFE channel tmp_lfe = !!(chmask & 0x08); if (tmp_lfe) chmask -= 0x08; // check for fbw channel layouts which are compatible with A/52 switch (chmask) { case 0x004: tmp_acmod = A52_ACMOD_MONO; break; case 0x003: tmp_acmod = A52_ACMOD_STEREO; break; case 0x007: tmp_acmod = A52_ACMOD_3_0; break; case 0x103: tmp_acmod = A52_ACMOD_2_1; break; case 0x107: tmp_acmod = A52_ACMOD_3_1; break; case 0x033: case 0x603: tmp_acmod = A52_ACMOD_2_2; break; case 0x037: case 0x607: tmp_acmod = A52_ACMOD_3_2; break; default: tmp_acmod = ch_to_acmod[ch-1]; break; } } if (acmod) *acmod = tmp_acmod; if (lfe) *lfe = tmp_lfe; return 0; } /** * WAV to A/52 channel mapping * note: thanks to Tebasuna for help in getting this order right. */ /** * Table to remap channels from WAV order to A/52 order. * [acmod][lfe][ch] */ static const uint8_t wav_chmap[8][2][6] = { { { 0, 1, }, { 0, 1, 2, } }, { { 0, }, { 0, 1, } }, { { 0, 1, }, { 0, 1, 2, } }, { { 0, 2, 1, }, { 0, 2, 1, 3, } }, { { 0, 1, 2, }, { 0, 1, 3, 2, } }, { { 0, 2, 1, 3, }, { 0, 2, 1, 4, 3, } }, { { 0, 1, 2, 3, 4, }, { 0, 1, 3, 4, 2, } }, { { 0, 2, 1, 3, 4, }, { 0, 2, 1, 4, 5, 3 } }, }; #define REMAP_WAV_TO_A52_COMMON(DATA_TYPE) \ { \ int i, j; \ DATA_TYPE *smp = samples; \ DATA_TYPE tmp[6]; \ int sample_size = sizeof(DATA_TYPE); \ for (i = 0; i < n*ch; i += ch) { \ memcpy(tmp, &smp[i], ch*sample_size); \ for (j = 0; j < ch; j++) \ smp[i+j] = tmp[wav_chmap[acmod][lfe][j]]; \ } \ } void aften_remap_wav_to_a52(void *samples, int n, int ch, A52SampleFormat fmt, int acmod) { int lfe; if (samples == NULL) { fprintf(stderr, "NULL parameter passed to aften_remap_wav_to_a52\n"); return; } lfe = 0; if (ch > a52_channels_tab[acmod]) lfe = 1; if (acmod < 3 || ((acmod == 4 || acmod == 6) && !lfe)) return; switch (fmt) { case A52_SAMPLE_FMT_U8: REMAP_WAV_TO_A52_COMMON(uint8_t) break; case A52_SAMPLE_FMT_S8: REMAP_WAV_TO_A52_COMMON(int8_t) break; case A52_SAMPLE_FMT_S16: REMAP_WAV_TO_A52_COMMON(int16_t) break; case A52_SAMPLE_FMT_S20: case A52_SAMPLE_FMT_S24: case A52_SAMPLE_FMT_S32: REMAP_WAV_TO_A52_COMMON(int32_t) break; case A52_SAMPLE_FMT_FLT: REMAP_WAV_TO_A52_COMMON(float) break; case A52_SAMPLE_FMT_DBL: REMAP_WAV_TO_A52_COMMON(double) break; } } /** * MPEG to A/52 channel mapping * Can be used for multi-channel DTS, MP2, or AAC */ #define REMAP_MPEG_TO_A52_COMMON(DATA_TYPE) \ { \ int i; \ DATA_TYPE *smp = samples; \ for (i = 0; i < n*ch; i += ch) { \ DATA_TYPE tmp = smp[i]; \ smp[i] = smp[i+1]; \ smp[i+1] = tmp; \ } \ } void aften_remap_mpeg_to_a52(void *samples, int n, int ch, A52SampleFormat fmt, int acmod) { if (samples == NULL) { fprintf(stderr, "NULL parameter passed to aften_remap_mpeg_to_a52\n"); return; } if (acmod <= 2 || !(acmod & 1)) return; switch (fmt) { case A52_SAMPLE_FMT_U8: REMAP_MPEG_TO_A52_COMMON(uint8_t) break; case A52_SAMPLE_FMT_S8: REMAP_MPEG_TO_A52_COMMON(int8_t) break; case A52_SAMPLE_FMT_S16: REMAP_MPEG_TO_A52_COMMON(int16_t) break; case A52_SAMPLE_FMT_S20: case A52_SAMPLE_FMT_S24: case A52_SAMPLE_FMT_S32: REMAP_MPEG_TO_A52_COMMON(int32_t) break; case A52_SAMPLE_FMT_FLT: REMAP_MPEG_TO_A52_COMMON(float) break; case A52_SAMPLE_FMT_DBL: REMAP_MPEG_TO_A52_COMMON(double) break; } } FloatType aften_get_float_type(void) { #ifdef CONFIG_DOUBLE return FLOAT_TYPE_DOUBLE; #else return FLOAT_TYPE_FLOAT; #endif } aften/libaften/window.c000066400000000000000000000043431132016273200154130ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * Copyright (c) 2006 Justin Ruggles * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file window.c * A/52 Kaiser-Bessel Derived Window */ #include "a52enc.h" #include "window.h" ALIGN16(FLOAT) a52_window[512] = {0}; static void apply_a52_window(FLOAT *samples) { int i; for (i = 0; i < 512; i += 2) { samples[i ] *= a52_window[i ]; samples[i+1] *= a52_window[i+1]; } } /** * Generate a Kaiser-Bessel Derived Window. * @param alpha Determines window shape * @param out_window Array to fill with window values * @param n Full window size * @param iter Number of iterations to use in BesselI0 */ static void kbd_window_init(FLOAT alpha, FLOAT *window, int n, int iter) { int i, j, n2; FLOAT a, x, bessel, sum; n2 = n >> 1; a = alpha * AFT_PI / n2; a = a*a; sum = 0.0; for (i = 0; i < n2; i++) { x = i * (n2 - i) * a; bessel = FCONST(1.0); for (j = iter; j > 0; j--) bessel = (bessel * x / (j*j)) + FCONST(1.0); sum += bessel; window[i] = sum; } sum += FCONST(1.0); for (i = 0; i < n2; i++) { window[i] = AFT_SQRT(window[i] / sum); window[n-1-i] = window[i]; } } void a52_window_init(A52WindowFunctions *winf) { kbd_window_init(5.0, a52_window, 512, 50); winf->apply_a52_window = apply_a52_window; #ifndef CONFIG_DOUBLE #ifdef HAVE_SSE if (cpu_caps_have_sse()) { winf->apply_a52_window = apply_a52_window_sse; } #endif #endif } aften/libaften/window.h000066400000000000000000000024611132016273200154170ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * Copyright (c) 2006 Justin Ruggles * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file window.h * A/52 Kaiser-Bessel Derived Window header */ #ifndef WINDOW_H #define WINDOW_H #include "common.h" #include "cpu_caps.h" #if defined(HAVE_MMX) || defined(HAVE_SSE) #include "x86/window.h" #endif extern FLOAT a52_window[512]; typedef struct A52WindowFunctions { /** * Apply the A/52 window function to 512 input samples. */ void (*apply_a52_window)(FLOAT *samples); } A52WindowFunctions; extern void a52_window_init(A52WindowFunctions *winf); #endif /* WINDOW_H */ aften/libaften/x86/000077500000000000000000000000001132016273200143615ustar00rootroot00000000000000aften/libaften/x86/asm_common.h000066400000000000000000000020761132016273200166670ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * * ASM support common header * Copyright (C) 2007 by Prakash Punnoor * prakash@punnoor.de * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; * version 2 of the License * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef ASM_COMMON_H #define ASM_COMMON_H #define _pushf _st(pushf) #define _popf _st(popf) #define _push(x) _st(push x) #define _pop(x) _st(pop x) #define _jz(x) _st(jz x) #define _cpuid _st(cpuid) #endif /* ASM_COMMON_H */ aften/libaften/x86/asm_support.h000066400000000000000000000017241132016273200171120ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * * ASM support header * Copyright (C) 2007 by Prakash Punnoor * prakash@punnoor.de * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; * version 2 of the License * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef ASM_SUPPORT_H #define ASM_SUPPORT_H #ifdef __GNUC__ #include "gas_support.h" #else #include "intelas_support.h" #endif #endif /* ASM_SUPPORT_H */ aften/libaften/x86/cpu_caps.c000066400000000000000000000132051132016273200163230ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * * Runtime CPU capabilities detection * Copyright (C) 2005-2007 by Prakash Punnoor * prakash@punnoor.de * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; * version 2 of the License * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "x86/cpu_caps.h" /* caps1 */ #define MMX_BIT 23 #define SSE_BIT 25 #define SSE2_BIT 26 /* caps2 */ #define SSE3_BIT 0 #define SSSE3_BIT 9 /* caps3 */ #define AMD_3DNOW_BIT 31 #define AMD_3DNOWEXT_BIT 30 #define AMD_SSE_MMX_BIT 22 #define CYRIX_MMXEXT_BIT 24 #ifdef HAVE_CPU_CAPS_DETECTION #if defined(_WIN64) && defined(_MSC_VER) /* MSVC doesn't support inline assembly in x64 mode */ #include static void cpu_caps_detect_x86(uint32_t *caps1, uint32_t *caps2, uint32_t *caps3) { int registers[4]; __cpuid(registers, 1); *caps1 = registers[3]; *caps2 = registers[2]; __cpuid(registers, 0x80000001); *caps3 = registers[3]; } #else #include "asm_support.h" // derived from loki_cpuinfo.c, 1997-98 by H. Dietz and R. Fisher // using infos from sandpile.org static void cpu_caps_detect_x86(uint32_t *caps1, uint32_t *caps2, uint32_t *caps3) { uint32_t c1, c2, c3; #if __GNUC__ #define param1 %0 #define param2 %1 #define param3 %2 asm volatile ( #else #define param1 c1 #define param2 c2 #define param3 c3 __asm { #endif _mov(_b, _s) // standard CPUID _mov(_(0x1), _eax) _cpuid _mov(_edx, param1) //caps1 - MMX, SSE, SSE2 _mov(_ecx, param2) //caps2 - SSE3 // extended CPUID _mov(_(0x80000001), _eax) _cpuid _mov(_edx, param3) //caps3 - 3DNOW!, 3DNOW!EXT, CYRIX-MMXEXT, AMD-MMX-SSE _mov(_s, _b) #if __GNUC__ :"=m"(c1), "=m"(c2), "=m"(c3) /* output */ : /* input */ :"%eax", "%ecx", "%edx", "%esi" /* clobbered registers */ ); #else } #endif *caps1 = c1; *caps2 = c2; *caps3 = c3; } #endif #endif static struct x86cpu_caps_s x86cpu_caps_compile = { 0, 0, 0, 0, 0, 0, 0, 0, 0}; static struct x86cpu_caps_s x86cpu_caps_detect = { 1, 1, 1, 1, 1, 1, 1, 1, 1}; struct x86cpu_caps_s x86cpu_caps_use = { 0, 0, 0, 0, 0, 0, 0, 0, 0}; void cpu_caps_detect(void) { /* compiled in SIMD routines */ #ifdef HAVE_MMX x86cpu_caps_compile.mmx = 1; #endif #ifdef HAVE_SSE x86cpu_caps_compile.sse = 1; #endif #ifdef HAVE_SSE2 x86cpu_caps_compile.sse2 = 1; #endif #ifdef HAVE_SSE3 x86cpu_caps_compile.sse3 = 1; #endif #ifdef HAVE_SSSE3 x86cpu_caps_compile.ssse3 = 1; #endif #ifdef HAVE_3DNOW x86cpu_caps_compile.amd_3dnow = 1; #endif #ifdef HAVE_SSE_MMX x86cpu_caps_compile.amd_sse_mmx = 1; #endif #ifdef HAVE_3DNOWEXT x86cpu_caps_compile.amd_3dnowext = 1; #endif /* end compiled in SIMD routines */ /* runtime detection */ #ifdef HAVE_CPU_CAPS_DETECTION { uint32_t caps1, caps2, caps3; cpu_caps_detect_x86(&caps1, &caps2, &caps3); x86cpu_caps_detect.mmx = (caps1 >> MMX_BIT) & 1; x86cpu_caps_detect.sse = (caps1 >> SSE_BIT) & 1; x86cpu_caps_detect.sse2 = (caps1 >> SSE2_BIT) & 1; x86cpu_caps_detect.sse3 = (caps2 >> SSE3_BIT) & 1; x86cpu_caps_detect.ssse3 = (caps2 >> SSSE3_BIT) & 1; x86cpu_caps_detect.amd_3dnow = (caps3 >> AMD_3DNOW_BIT) & 1; x86cpu_caps_detect.amd_3dnowext = (caps3 >> AMD_3DNOWEXT_BIT) & 1; x86cpu_caps_detect.amd_sse_mmx = (caps3 >> AMD_SSE_MMX_BIT) & 1; /* FIXME: For Cyrix MMXEXT detect Cyrix CPU first! */ /* x86cpu_caps.cyrix_mmxext = (caps3 >> CYRIX_MMXEXT_BIT) & 1; */ } #endif /*HAVE_CPU_CAPS_DETECTION*/ /* end runtime detection */ x86cpu_caps_use.mmx = x86cpu_caps_detect.mmx & x86cpu_caps_compile.mmx; x86cpu_caps_use.sse = x86cpu_caps_detect.sse & x86cpu_caps_compile.sse; x86cpu_caps_use.sse2 = x86cpu_caps_detect.sse2 & x86cpu_caps_compile.sse2; x86cpu_caps_use.sse3 = x86cpu_caps_detect.sse3 & x86cpu_caps_compile.sse3; x86cpu_caps_use.ssse3 = x86cpu_caps_detect.ssse3 & x86cpu_caps_compile.ssse3; x86cpu_caps_use.amd_3dnow = x86cpu_caps_detect.amd_3dnow & x86cpu_caps_compile.amd_3dnow; x86cpu_caps_use.amd_3dnowext = x86cpu_caps_detect.amd_3dnowext & x86cpu_caps_compile.amd_3dnowext; x86cpu_caps_use.amd_sse_mmx = x86cpu_caps_detect.amd_sse_mmx & x86cpu_caps_compile.amd_sse_mmx; } void apply_simd_restrictions(AftenSimdInstructions *simd_instructions) { x86cpu_caps_use.mmx &= simd_instructions->mmx; x86cpu_caps_use.sse &= simd_instructions->sse; x86cpu_caps_use.sse2 &= simd_instructions->sse2; x86cpu_caps_use.sse3 &= simd_instructions->sse3; x86cpu_caps_use.ssse3 &= simd_instructions->ssse3; x86cpu_caps_use.amd_3dnow &= simd_instructions->amd_3dnow; x86cpu_caps_use.amd_3dnowext &= simd_instructions->amd_3dnowext; x86cpu_caps_use.amd_sse_mmx &= simd_instructions->amd_sse_mmx; } aften/libaften/x86/cpu_caps.h000066400000000000000000000044411132016273200163320ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * * Runtime CPU capabilities detection header * Copyright (C) 2005-2007 by Prakash Punnoor * prakash@punnoor.de * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; * version 2 of the License * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef X86_CPU_CAPS_H #define X86_CPU_CAPS_H #include "aften-types.h" #include "common.h" struct x86cpu_caps_s { int mmx; int sse; int sse2; int sse3; int ssse3; int amd_3dnow; int amd_3dnowext; int amd_sse_mmx; int cyrix_mmxext; }; extern struct x86cpu_caps_s x86cpu_caps_use; void cpu_caps_detect(void); void apply_simd_restrictions(AftenSimdInstructions *simd_instructions); static inline int cpu_caps_have_mmx(void); static inline int cpu_caps_have_sse(void); static inline int cpu_caps_have_sse2(void); static inline int cpu_caps_have_sse3(void); static inline int cpu_caps_have_ssse3(void); static inline int cpu_caps_have_3dnow(void); static inline int cpu_caps_have_3dnowext(void); static inline int cpu_caps_have_ssemmx(void); static inline int cpu_caps_have_mmx(void) { return x86cpu_caps_use.mmx; } static inline int cpu_caps_have_sse(void) { return x86cpu_caps_use.sse; } static inline int cpu_caps_have_sse2(void) { return x86cpu_caps_use.sse2; } static inline int cpu_caps_have_sse3(void) { return x86cpu_caps_use.sse3; } static inline int cpu_caps_have_ssse3(void) { return x86cpu_caps_use.ssse3; } static inline int cpu_caps_have_3dnow(void) { return x86cpu_caps_use.amd_3dnow; } static inline int cpu_caps_have_3dnowext(void) { return x86cpu_caps_use.amd_3dnowext; } static inline int cpu_caps_have_ssemmx(void) { return x86cpu_caps_use.amd_sse_mmx; } #endif /* not X86_CPU_CAPS_H */ aften/libaften/x86/exponent.h000066400000000000000000000031271132016273200163750ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * * x86 exponent functions header * Copyright (c) 2007 Prakash Punnoor * 2006 Justin Ruggles * * Based on "The simplest AC3 encoder" from FFmpeg * Copyright (c) 2000 Fabrice Bellard. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; * version 2 of the License * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ /** * @file exponent.h * A/52 x86 exponent header */ #ifndef X86_EXPONENT_H #define X86_EXPONENT_H #include "common.h" #ifdef HAVE_SSE2 extern void exponent_min_sse2(uint8_t *exp, uint8_t *exp1, int n); extern void encode_exp_blk_ch_sse2(uint8_t *exp, int ncoefs, int exp_strategy); extern int exponent_sum_square_error_sse2(uint8_t *exp0, uint8_t *exp1, int ncoefs); #endif #ifdef HAVE_MMX extern void exponent_min_mmx(uint8_t *exp, uint8_t *exp1, int n); extern void encode_exp_blk_ch_mmx(uint8_t *exp, int ncoefs, int exp_strategy); extern int exponent_sum_square_error_mmx(uint8_t *exp0, uint8_t *exp1, int ncoefs); #endif #endif /* X86_EXPONENT_H */ aften/libaften/x86/exponent_mmx.c000066400000000000000000000214641132016273200172550ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * * MMX exponent functions * Copyright (c) 2007 Prakash Punnoor * 2006 Justin Ruggles * * Based on "The simplest AC3 encoder" from FFmpeg * Copyright (c) 2000 Fabrice Bellard. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; * version 2 of the License * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ /** * @file x86_mmx_exponent.c * A/52 mmx optimized exponent functions */ #include "a52enc.h" #include "x86/simd_support.h" void exponent_min_mmx(uint8_t *exp, uint8_t *exp1, int n) { int i; for (i = 0; i < (n & ~7); i += 8) { __m64 vexp = *(__m64*)&exp[i]; __m64 vexp1 = *(__m64*)&exp1[i]; __m64 vmask = _mm_cmpgt_pi8(vexp, vexp1); vexp = _mm_andnot_si64(vmask, vexp); vexp1 = _mm_and_si64(vmask, vexp1); vexp = _mm_or_si64(vexp, vexp1); *(__m64*)&exp[i] = vexp; } switch (n & 7) { case 7: exp[i] = MIN(exp[i], exp1[i]); ++i; case 6: exp[i] = MIN(exp[i], exp1[i]); ++i; case 5: exp[i] = MIN(exp[i], exp1[i]); ++i; case 4: exp[i] = MIN(exp[i], exp1[i]); ++i; case 3: exp[i] = MIN(exp[i], exp1[i]); ++i; case 2: exp[i] = MIN(exp[i], exp1[i]); ++i; case 1: exp[i] = MIN(exp[i], exp1[i]); case 0: ; } _mm_empty(); } void encode_exp_blk_ch_mmx(uint8_t *exp, int ncoefs, int exp_strategy) { int grpsize, ngrps, i, k, exp_min1, exp_min2; uint8_t v; ngrps = nexpgrptab[exp_strategy-1][ncoefs] * 3; grpsize = exp_strategy + (exp_strategy == EXP_D45); // for D15 strategy, there is no need to group/ungroup exponents switch (grpsize) { case 1: { // constraint for DC exponent exp[0] = MIN(exp[0], 15); // Decrease the delta between each groups to within 2 // so that they can be differentially encoded for (i = 1; i <= ngrps; i++) exp[i] = MIN(exp[i], exp[i-1]+2); for (i = ngrps-1; i >= 0; i--) exp[i] = MIN(exp[i], exp[i+1]+2); break; } // for each group, compute the minimum exponent case 2: { ALIGN16(uint16_t) exp1[256]; ALIGN16(const union __m64ui) vmask = {{0x00ff00ff, 0x00ff00ff}}; i=0; k=1; for (; i < (ngrps & ~3); i += 4, k += 8) { __m64 v1 = *(__m64*)&exp[k]; __m64 v2 = _mm_srli_si64(v1, 8); __m64 vcmask; v1 = _mm_and_si64(v1, vmask.v); //v1 = _mm_min_pi8(v1, v2); vcmask = _mm_cmpgt_pi8(v1, v2); v1 = _mm_andnot_si64(vcmask, v1); v2 = _mm_and_si64(vcmask, v2); v1 = _mm_or_si64(v1, v2); *(__m64*)&exp1[i] = v1; } switch (ngrps & 3) { case 3: exp1[i] = MIN(exp[k], exp[k+1]); ++i; k += 2; case 2: exp1[i] = MIN(exp[k], exp[k+1]); ++i; k += 2; case 1: exp1[i] = MIN(exp[k], exp[k+1]); case 0: ; } // constraint for DC exponent exp[0] = MIN(exp[0], 15); // Decrease the delta between each groups to within 2 // so that they can be differentially encoded exp1[0] = MIN(exp1[0], (uint16_t)exp[0]+2); for (i = 1; i < ngrps; i++) exp1[i] = MIN(exp1[i], exp1[i-1]+2); for(i = ngrps-2; i >= 0; i--) exp1[i] = MIN(exp1[i], exp1[i+1]+2); // now we have the exponent values the decoder will see exp[0] = MIN(exp[0], exp1[0]+2); // DC exponent is handled separately i=0; k=1; for(; i < (ngrps & ~3); i += 4, k += 8) { __m64 v1 = *(__m64*)&exp1[i]; __m64 v2 = _mm_slli_si64(v1, 8); v1 = _mm_or_si64(v1, v2); *(__m64*)&exp[k] = v1; } switch (ngrps & 3) { case 3: v = (uint8_t)exp1[i]; exp[k] = v; exp[k+1] = v; ++i; k += 2; case 2: v = (uint8_t)exp1[i]; exp[k] = v; exp[k+1] = v; ++i; k += 2; case 1: v = (uint8_t)exp1[i]; exp[k] = v; exp[k+1] = v; case 0: ; } break; } default: { ALIGN16(uint32_t) exp1[256]; ALIGN16(const union __m64ui) vmask2 = {{0x000000ff, 0x000000ff}}; i=0;k=1; for (; i < (ngrps & ~1); i += 2, k += 8) { __m64 v1 = *(__m64*)&exp[k]; __m64 v2 = _mm_srli_si64(v1, 8); //v1 = _mm_min_pi8(v1, v2); __m64 vcmask = _mm_cmpgt_pi8(v1, v2); v1 = _mm_andnot_si64(vcmask, v1); v2 = _mm_and_si64(vcmask, v2); v1 = _mm_or_si64(v1, v2); v2 = _mm_srli_si64(v1, 16); //v1 = _mm_min_pi8(v1, v2); vcmask = _mm_cmpgt_pi8(v1, v2); v1 = _mm_andnot_si64(vcmask, v1); v2 = _mm_and_si64(vcmask, v2); v1 = _mm_or_si64(v1, v2); v1 = _mm_and_si64(v1, vmask2.v); *(__m64*)&exp1[i] = v1; } if (ngrps & 1) { exp_min1 = MIN(exp[k ], exp[k+1]); exp_min2 = MIN(exp[k+2], exp[k+3]); exp1[i] = MIN(exp_min1, exp_min2); } // constraint for DC exponent exp[0] = MIN(exp[0], 15); // Decrease the delta between each groups to within 2 // so that they can be differentially encoded exp1[0] = MIN(exp1[0], (uint32_t)exp[0]+2); for (i = 1; i < ngrps; i++) exp1[i] = MIN(exp1[i], exp1[i-1]+2); for (i = ngrps-2; i >= 0; i--) exp1[i] = MIN(exp1[i], exp1[i+1]+2); // now we have the exponent values the decoder will see exp[0] = MIN(exp[0], exp1[0]+2); // DC exponent is handled separately i=0; k=1; for (; i < (ngrps & ~1); i += 2, k += 8) { __m64 v1 = *(__m64*)&exp1[i]; __m64 v2 = _mm_slli_si64(v1, 8); v1 = _mm_or_si64(v1, v2); v2 = _mm_slli_si64(v1, 16); v1 = _mm_or_si64(v1, v2); *(__m64*)&exp[k] = v1; } if (ngrps & 1) { v = exp1[i]; exp[k] = v; exp[k+1] = v; exp[k+2] = v; exp[k+3] = v; } break; } } _mm_empty(); } int exponent_sum_square_error_mmx(uint8_t *exp0, uint8_t *exp1, int ncoefs) { int i, err; int exp_error = 0; union { __m64 v; int32_t res[2]; } ures; __m64 vzero = _mm_setzero_si64(); __m64 vres = vzero; for (i = 0; i < (ncoefs & ~7); i += 8) { __m64 vexp = *(__m64*)&exp0[i]; __m64 vexp2 = *(__m64*)&exp1[i]; #if 0 //safer but needed? __m64 vexphi = _mm_unpackhi_pi8(vexp, vzero); __m64 vexp2hi = _mm_unpackhi_pi8(vexp2, vzero); __m64 vexplo = _mm_unpacklo_pi8(vexp, vzero); __m64 vexp2lo = _mm_unpacklo_pi8(vexp2, vzero); __m64 verrhi = _mm_sub_pi16(vexphi, vexp2hi); __m64 verrlo = _mm_sub_pi16(vexplo, vexp2lo); #else __m64 verr = _mm_sub_pi8(vexp, vexp2); __m64 vsign = _mm_cmpgt_pi8(vzero, verr); __m64 verrhi = _mm_unpackhi_pi8(verr, vsign); __m64 verrlo = _mm_unpacklo_pi8(verr, vsign); #endif verrhi = _mm_madd_pi16(verrhi, verrhi); verrlo = _mm_madd_pi16(verrlo, verrlo); verrhi = _mm_add_pi32(verrhi, verrlo); vres = _mm_add_pi32(vres, verrhi); } ures.v = vres; exp_error += ures.res[0]+ures.res[1]; switch (ncoefs & 7) { case 7: err = exp0[i] - exp1[i]; exp_error += (err * err); ++i; case 6: err = exp0[i] - exp1[i]; exp_error += (err * err); ++i; case 5: err = exp0[i] - exp1[i]; exp_error += (err * err); ++i; case 4: err = exp0[i] - exp1[i]; exp_error += (err * err); ++i; case 3: err = exp0[i] - exp1[i]; exp_error += (err * err); ++i; case 2: err = exp0[i] - exp1[i]; exp_error += (err * err); ++i; case 1: err = exp0[i] - exp1[i]; exp_error += (err * err); case 0: ; } _mm_empty(); return exp_error; } aften/libaften/x86/exponent_sse2.c000066400000000000000000000224501132016273200173240ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * * MMX exponent functions * Copyright (c) 2007 Prakash Punnoor * 2006 Justin Ruggles * * Based on "The simplest AC3 encoder" from FFmpeg * Copyright (c) 2000 Fabrice Bellard. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; * version 2 of the License * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ /** * @file x86_sse2_exponent.c * A/52 sse2 optimized exponent functions */ #include "a52enc.h" #include "x86/simd_support.h" void exponent_min_sse2(uint8_t *exp, uint8_t *exp1, int n) { int i; for (i = 0; i < (n & ~15); i += 16) { __m128i vexp = _mm_loadu_si128((__m128i*)&exp[i]); __m128i vexp1 = _mm_loadu_si128((__m128i*)&exp1[i]); vexp = _mm_min_epu8(vexp, vexp1); _mm_storeu_si128 ((__m128i*)&exp[i], vexp); } for (; i < n; ++i) exp[i] = MIN(exp[i], exp1[i]); } void encode_exp_blk_ch_sse2(uint8_t *exp, int ncoefs, int exp_strategy) { int grpsize, ngrps, i, k, exp_min1, exp_min2; uint8_t v; ngrps = nexpgrptab[exp_strategy-1][ncoefs] * 3; grpsize = exp_strategy + (exp_strategy == EXP_D45); // for D15 strategy, there is no need to group/ungroup exponents switch (grpsize) { case 1: { // constraint for DC exponent exp[0] = MIN(exp[0], 15); // Decrease the delta between each groups to within 2 // so that they can be differentially encoded for (i = 1; i <= ngrps; i++) exp[i] = MIN(exp[i], exp[i-1]+2); for (i = ngrps-1; i >= 0; i--) exp[i] = MIN(exp[i], exp[i+1]+2); return; } // for each group, compute the minimum exponent case 2: { ALIGN16(uint16_t) exp1[256]; ALIGN16(const union __m128iui) vmask = {{0x00ff00ff, 0x00ff00ff, 0x00ff00ff, 0x00ff00ff}}; i=0; k=1; for(; i < (ngrps & ~7); i += 8, k += 16) { __m128i v1 = _mm_loadu_si128((__m128i*)&exp[k]); __m128i v2 = _mm_srli_si128(v1, 1); v1 = _mm_and_si128(v1, vmask.v); v1 = _mm_min_epu8(v1, v2); _mm_store_si128((__m128i*)&exp1[i], v1); } switch (ngrps & 7) { case 7: exp1[i] = MIN(exp[k], exp[k+1]); ++i; k += 2; case 6: exp1[i] = MIN(exp[k], exp[k+1]); ++i; k += 2; case 5: exp1[i] = MIN(exp[k], exp[k+1]); ++i; k += 2; case 4: exp1[i] = MIN(exp[k], exp[k+1]); ++i; k += 2; case 3: exp1[i] = MIN(exp[k], exp[k+1]); ++i; k += 2; case 2: exp1[i] = MIN(exp[k], exp[k+1]); ++i; k += 2; case 1: exp1[i] = MIN(exp[k], exp[k+1]); case 0: ; } // constraint for DC exponent exp[0] = MIN(exp[0], 15); // Decrease the delta between each groups to within 2 // so that they can be differentially encoded exp1[0] = MIN(exp1[0], (uint16_t)exp[0]+2); for (i = 1; i < ngrps; i++) exp1[i] = MIN(exp1[i], exp1[i-1]+2); for (i = ngrps-2; i >= 0; i--) exp1[i] = MIN(exp1[i], exp1[i+1]+2); // now we have the exponent values the decoder will see exp[0] = MIN(exp[0], exp1[0]+2); // DC exponent is handled separately i=0; k=1; for (; i < (ngrps & ~7); i += 8, k += 16) { __m128i v1 = _mm_load_si128((__m128i*)&exp1[i]); __m128i v2 = _mm_slli_si128(v1, 1); v1 = _mm_or_si128(v1, v2); _mm_storeu_si128((__m128i*)&exp[k], v1); } switch (ngrps & 7) { case 7: v = (uint8_t)exp1[i]; exp[k] = v; exp[k+1] = v; ++i; k += 2; case 6: v = (uint8_t)exp1[i]; exp[k] = v; exp[k+1] = v; ++i; k += 2; case 5: v = (uint8_t)exp1[i]; exp[k] = v; exp[k+1] = v; ++i; k += 2; case 4: v = (uint8_t)exp1[i]; exp[k] = v; exp[k+1] = v; ++i; k += 2; case 3: v = (uint8_t)exp1[i]; exp[k] = v; exp[k+1] = v; ++i; k += 2; case 2: v = (uint8_t)exp1[i]; exp[k] = v; exp[k+1] = v; ++i; k += 2; case 1: v = (uint8_t)exp1[i]; exp[k] = v; exp[k+1] = v; case 0: ; } return; } default: { ALIGN16(uint32_t) exp1[256]; ALIGN16(const union __m128iui) vmask2 = {{0x000000ff, 0x000000ff, 0x000000ff, 0x000000ff}}; i=0; k=1; for (; i < (ngrps & ~3); i += 4, k += 16) { __m128i v1 = _mm_loadu_si128((__m128i*)&exp[k]); __m128i v2 = _mm_srli_si128(v1, 1); v1 = _mm_min_epu8(v1, v2); v2 = _mm_srli_si128(v1, 2); v1 = _mm_min_epu8(v1, v2); v1 = _mm_and_si128(v1, vmask2.v); _mm_store_si128((__m128i*)&exp1[i], v1); } switch (ngrps & 3) { case 3: exp_min1 = MIN(exp[k ], exp[k+1]); exp_min2 = MIN(exp[k+2], exp[k+3]); exp1[i] = MIN(exp_min1, exp_min2); ++i; k += 4; case 2: exp_min1 = MIN(exp[k ], exp[k+1]); exp_min2 = MIN(exp[k+2], exp[k+3]); exp1[i] = MIN(exp_min1, exp_min2); ++i; k += 4; case 1: exp_min1 = MIN(exp[k ], exp[k+1]); exp_min2 = MIN(exp[k+2], exp[k+3]); exp1[i] = MIN(exp_min1, exp_min2); case 0: ; } // constraint for DC exponent exp[0] = MIN(exp[0], 15); // Decrease the delta between each groups to within 2 // so that they can be differentially encoded exp1[0] = MIN(exp1[0], (uint32_t)exp[0]+2); for (i = 1; i < ngrps; i++) exp1[i] = MIN(exp1[i], exp1[i-1]+2); for (i = ngrps-2; i >= 0; i--) exp1[i] = MIN(exp1[i], exp1[i+1]+2); // now we have the exponent values the decoder will see exp[0] = MIN(exp[0], exp1[0]+2); // DC exponent is handled separately i=0; k=1; for (; i < (ngrps & ~3); i += 4, k += 16) { __m128i v1 = _mm_load_si128((__m128i*)&exp1[i]); __m128i v2 = _mm_slli_si128(v1, 1); v1 = _mm_or_si128(v1, v2); v2 = _mm_slli_si128(v1, 2); v1 = _mm_or_si128(v1, v2); _mm_storeu_si128((__m128i*)&exp[k], v1); } switch (ngrps & 3) { case 3: v = exp1[i]; exp[k] = v; exp[k+1] = v; exp[k+2] = v; exp[k+3] = v; ++i; k += 4; case 2: v = exp1[i]; exp[k] = v; exp[k+1] = v; exp[k+2] = v; exp[k+3] = v; ++i; k += 4; case 1: v = exp1[i]; exp[k] = v; exp[k+1] = v; exp[k+2] = v; exp[k+3] = v; case 0: ; } return; } } } int exponent_sum_square_error_sse2(uint8_t *exp0, uint8_t *exp1, int ncoefs) { int i, err; int exp_error = 0; union { __m128i v; int32_t res[4]; } ures; __m128i vzero = _mm_setzero_si128(); __m128i vres = vzero; for (i = 0; i < (ncoefs & ~15); i+=16) { __m128i vexp = _mm_loadu_si128((__m128i*)&exp0[i]); __m128i vexp2 = _mm_load_si128((__m128i*)&exp1[i]); #if 0 //safer but needed? __m128i vexphi = _mm_unpackhi_epi8(vexp, vzero); __m128i vexp2hi = _mm_unpackhi_epi8(vexp2, vzero); __m128i vexplo = _mm_unpacklo_epi8(vexp, vzero); __m128i vexp2lo = _mm_unpacklo_epi8(vexp2, vzero); __m128i verrhi = _mm_sub_epi16(vexphi, vexp2hi); __m128i verrlo = _mm_sub_epi16(vexplo, vexp2lo); #else __m128i verr = _mm_sub_epi8(vexp, vexp2); __m128i vsign = _mm_cmplt_epi8(verr, vzero); __m128i verrhi = _mm_unpackhi_epi8(verr, vsign); __m128i verrlo = _mm_unpacklo_epi8(verr, vsign); #endif verrhi = _mm_madd_epi16(verrhi, verrhi); verrlo = _mm_madd_epi16(verrlo, verrlo); verrhi = _mm_add_epi32(verrhi, verrlo); vres = _mm_add_epi32(vres, verrhi); } _mm_store_si128(&ures.v, vres); ures.res[0]+=ures.res[1]; ures.res[2]+=ures.res[3]; exp_error += ures.res[0]+ures.res[2]; for (; i < ncoefs; ++i) { err = exp0[i] - exp1[i]; exp_error += (err * err); } return exp_error; } aften/libaften/x86/gas_support.h000066400000000000000000000030461132016273200171030ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * * GNU Assembler syntax support * Copyright (C) 2007 by Prakash Punnoor * prakash@punnoor.de * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; * version 2 of the License * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef GAS_SUPPORT_H #define GAS_SUPPORT_H #define _st(x) #x"\n\t" #define __st(x,y) #x","#y"\n\t" #define _mov(x, y) __st(mov x, y) #define _xor(x, y) __st(xor x, y) #define _test(x, y) __st(test x, y) #define _(x) $##x #define _l(x) #x":\n\t" #define _eax %%eax #define _ebx %%ebx #define _ecx %%ecx #define _edx %%edx #define _esi %%esi #include "asm_common.h" #ifdef __LP64__ #define _a %%rax #define _b %%rbx #define _c %%rcx #define _d %%rdx #define _s %%rsi #else #define _a _eax #define _b _ebx #define _c _ecx #define _d _edx #define _s _esi #endif #endif /* GAS_SUPPORT_H */ aften/libaften/x86/intelas_support.h000066400000000000000000000030421132016273200177640ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * * Intel Assembler syntax support * Copyright (C) 2007 by Prakash Punnoor * prakash@punnoor.de * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; * version 2 of the License * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef INTELAS_SUPPORT_H #define INTELAS_SUPPORT_H #define _st(x) x #define __st(x,y) x, y #define _mov(x, y) __st(mov y, x) #define _xor(x, y) __st(xor y, x) #define _test(x, y) __st(test y, x) #define _(x) x #define _l(x) x##: #define _eax EAX #define _ebx EBX #define _ecx ECX #define _edx EDX #define _esi ESI #include "asm_common.h" #if defined(_M_X64) || defined (__LP64__) #define _a RAX #define _b RBX #define _c RCX #define _d RDX #define _s RSI #else #define _a _eax #define _b _ebx #define _c _ecx #define _d _edx #define _s _esi #endif #endif /* INTELAS_SUPPORT_H */ aften/libaften/x86/mdct.h000066400000000000000000000041021132016273200154560ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * * x86 MDCT functions * This file is derived from libvorbis lancer patch * Copyright (c) 2006-2007 prakash@punnoor.de * Copyright (c) 2006, blacksword8192@hotmail.com * Copyright (c) 2002, 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. */ /** * @file x86/mdct.h * x86 MDCT header */ #ifndef X86_MDCT_H #define X86_MDCT_H #include "common.h" struct A52Context; struct A52ThreadContext; #ifndef CONFIG_DOUBLE #ifdef HAVE_SSE extern void mdct_init_sse(struct A52Context *ctx); #endif #ifdef HAVE_SSE3 extern void mdct_init_sse3(struct A52Context *ctx); #endif #endif #endif /* X86_MDCT_H */ aften/libaften/x86/mdct_common_sse.c000066400000000000000000000524771132016273200177150ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * * SSE MDCT functions * This file is derived from libvorbis lancer patch * Copyright (c) 2006-2007 prakash@punnoor.de * Copyright (c) 2006, blacksword8192@hotmail.com * Copyright (c) 2002, 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. */ /** * @file x86/mdct_common_sse.c * MDCT, common functions for the SSE and SSE3 instruction sets */ #include "a52enc.h" #include "x86/simd_support.h" #include "mdct_common_sse.h" static const union __m128ui PCS_NNRR = {{0x80000000, 0x80000000, 0x00000000, 0x00000000}}; static const union __m128ui PCS_RNRN = {{0x00000000, 0x80000000, 0x00000000, 0x80000000}}; static const union __m128ui PCS_RRNN = {{0x00000000, 0x00000000, 0x80000000, 0x80000000}}; static const union __m128ui PCS_RNNR = {{0x80000000, 0x00000000, 0x00000000, 0x80000000}}; static const union __m128ui PCS_RRRR = {{0x80000000, 0x80000000, 0x80000000, 0x80000000}}; static const union __m128ui PCS_NRRN = {{0x00000000, 0x80000000, 0x80000000, 0x00000000}}; static const union __m128f PFV_0P5 = {{0.5f, 0.5f, 0.5f, 0.5f}}; /** 8 point butterfly */ static inline void mdct_butterfly_8_sse(FLOAT *x) { __m128 XMM0, XMM1, XMM2, XMM3; XMM0 = _mm_load_ps(x+4); XMM1 = _mm_load_ps(x ); XMM2 = XMM0; XMM0 = _mm_sub_ps(XMM0, XMM1); XMM2 = _mm_add_ps(XMM2, XMM1); XMM1 = XMM0; XMM3 = XMM2; XMM0 = _mm_shuffle_ps(XMM0, XMM0, _MM_SHUFFLE(3,2,3,2)); XMM1 = _mm_shuffle_ps(XMM1, XMM1, _MM_SHUFFLE(0,1,0,1)); XMM2 = _mm_shuffle_ps(XMM2, XMM2, _MM_SHUFFLE(3,2,3,2)); XMM3 = _mm_shuffle_ps(XMM3, XMM3, _MM_SHUFFLE(1,0,1,0)); XMM1 = _mm_xor_ps(XMM1, PCS_NRRN.v); XMM3 = _mm_xor_ps(XMM3, PCS_NNRR.v); XMM0 = _mm_add_ps(XMM0, XMM1); XMM2 = _mm_add_ps(XMM2, XMM3); _mm_store_ps(x , XMM0); _mm_store_ps(x+4, XMM2); } /** 16 point butterfly */ void mdct_butterfly_16_sse(FLOAT *x) { static _MM_ALIGN16 const float PFV0[4] = { AFT_PI2_8, AFT_PI2_8, 1.f, -1.f}; static _MM_ALIGN16 const float PFV1[4] = { AFT_PI2_8, -AFT_PI2_8, 0.f, 0.f}; static _MM_ALIGN16 const float PFV2[4] = { AFT_PI2_8, AFT_PI2_8, 1.f, 1.f}; static _MM_ALIGN16 const float PFV3[4] = {-AFT_PI2_8, AFT_PI2_8, 0.f, 0.f}; __m128 XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7; XMM3 = _mm_load_ps(x+12); XMM0 = _mm_load_ps(x ); XMM1 = _mm_load_ps(x+ 4); XMM2 = _mm_load_ps(x+ 8); XMM4 = XMM3; XMM5 = XMM0; XMM0 = _mm_sub_ps(XMM0, XMM2); XMM3 = _mm_sub_ps(XMM3, XMM1); XMM2 = _mm_add_ps(XMM2, XMM5); XMM4 = _mm_add_ps(XMM4, XMM1); XMM1 = XMM0; XMM5 = XMM3; _mm_store_ps(x+ 8, XMM2); _mm_store_ps(x+12, XMM4); XMM0 = _mm_shuffle_ps(XMM0, XMM0, _MM_SHUFFLE(2,3,1,1)); XMM2 = _mm_load_ps(PFV0); XMM1 = _mm_shuffle_ps(XMM1, XMM1, _MM_SHUFFLE(2,3,0,0)); XMM4 = _mm_load_ps(PFV1); XMM3 = _mm_shuffle_ps(XMM3, XMM3, _MM_SHUFFLE(3,2,0,0)); XMM6 = _mm_load_ps(PFV2); XMM5 = _mm_shuffle_ps(XMM5, XMM5, _MM_SHUFFLE(3,2,1,1)); XMM7 = _mm_load_ps(PFV3); XMM0 = _mm_mul_ps(XMM0, XMM2); XMM1 = _mm_mul_ps(XMM1, XMM4); XMM3 = _mm_mul_ps(XMM3, XMM6); XMM5 = _mm_mul_ps(XMM5, XMM7); XMM0 = _mm_add_ps(XMM0, XMM1); XMM3 = _mm_add_ps(XMM3, XMM5); _mm_store_ps(x , XMM0); _mm_store_ps(x+ 4, XMM3); mdct_butterfly_8_sse(x); mdct_butterfly_8_sse(x+8); } static void mdct_butterflies_sse(MDCTContext *mdct, FLOAT *x, int points) { FLOAT *trig = mdct->trig_butterfly_first; int stages = mdct->log2n-5; int i, j; if (--stages > 0) mdct->mdct_butterfly_first(trig, x, points); for (i = 1; --stages > 0; i++) for (j = 0; j < (1<mdct_butterfly_generic(mdct, x+(points>>i)*j, points>>i, 4<mdct_butterfly_32(x+j); } static void mdct_sse(MDCTThreadContext *tmdct, FLOAT *out, FLOAT *in) { MDCTContext *mdct = tmdct->mdct; int n = mdct->n; int n2 = n>>1; int n4 = n>>2; int n8 = n>>3; FLOAT *w = tmdct->buffer; FLOAT *w2 = w+n2; float *x0 = in+n2+n4-8; float *x1 = in+n2+n4; float *T = mdct->trig_forward; int i, j; #ifdef __INTEL_COMPILER #pragma warning(disable : 592) #endif for (i = 0, j = n2-2; i < n8; i += 4, j -= 4) { __m128 XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7; XMM0 = _mm_load_ps(x0 + 4); XMM4 = _mm_load_ps(x0 ); XMM1 = _mm_load_ps(x0+i*4+ 8); XMM5 = _mm_load_ps(x0+i*4+12); XMM2 = _mm_load_ps(T ); XMM3 = _mm_load_ps(T+ 4); XMM6 = _mm_load_ps(T+ 8); XMM7 = _mm_load_ps(T+12); XMM0 = _mm_shuffle_ps(XMM0, XMM0, _MM_SHUFFLE(0,1,2,3)); XMM4 = _mm_shuffle_ps(XMM4, XMM4, _MM_SHUFFLE(0,1,2,3)); XMM0 = _mm_add_ps(XMM0, XMM1); XMM4 = _mm_add_ps(XMM4, XMM5); XMM1 = XMM0; XMM5 = XMM4; XMM0 = _mm_shuffle_ps(XMM0, XMM0, _MM_SHUFFLE(0,0,3,3)); XMM1 = _mm_shuffle_ps(XMM1, XMM1, _MM_SHUFFLE(2,2,1,1)); XMM4 = _mm_shuffle_ps(XMM4, XMM4, _MM_SHUFFLE(0,0,3,3)); XMM5 = _mm_shuffle_ps(XMM5, XMM5, _MM_SHUFFLE(2,2,1,1)); XMM0 = _mm_mul_ps(XMM0, XMM2); XMM1 = _mm_mul_ps(XMM1, XMM3); XMM4 = _mm_mul_ps(XMM4, XMM6); XMM5 = _mm_mul_ps(XMM5, XMM7); XMM0 = _mm_sub_ps(XMM0, XMM1); XMM4 = _mm_sub_ps(XMM4, XMM5); _mm_storel_pi((__m64*)(w2+i ), XMM0); _mm_storeh_pi((__m64*)(w2+j ), XMM0); _mm_storel_pi((__m64*)(w2+i+2), XMM4); _mm_storeh_pi((__m64*)(w2+j-2), XMM4); x0 -= 8; T += 16; } x0 = in; x1 = in+n2-8; for (; i < n4; i += 4, j -= 4) { __m128 XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7; XMM1 = _mm_load_ps(x1+4); XMM5 = _mm_load_ps(x1 ); XMM0 = _mm_load_ps(x0 ); XMM4 = _mm_load_ps(x0+4); XMM2 = _mm_load_ps(T ); XMM3 = _mm_load_ps(T+ 4); XMM6 = _mm_load_ps(T+ 8); XMM7 = _mm_load_ps(T+12); XMM1 = _mm_shuffle_ps(XMM1, XMM1, _MM_SHUFFLE(0,1,2,3)); XMM5 = _mm_shuffle_ps(XMM5, XMM5, _MM_SHUFFLE(0,1,2,3)); XMM0 = _mm_sub_ps(XMM0, XMM1); XMM4 = _mm_sub_ps(XMM4, XMM5); XMM1 = XMM0; XMM5 = XMM4; XMM0 = _mm_shuffle_ps(XMM0, XMM0, _MM_SHUFFLE(0,0,3,3)); XMM1 = _mm_shuffle_ps(XMM1, XMM1, _MM_SHUFFLE(2,2,1,1)); XMM4 = _mm_shuffle_ps(XMM4, XMM4, _MM_SHUFFLE(0,0,3,3)); XMM5 = _mm_shuffle_ps(XMM5, XMM5, _MM_SHUFFLE(2,2,1,1)); XMM0 = _mm_mul_ps(XMM0, XMM2); XMM1 = _mm_mul_ps(XMM1, XMM3); XMM4 = _mm_mul_ps(XMM4, XMM6); XMM5 = _mm_mul_ps(XMM5, XMM7); XMM0 = _mm_add_ps(XMM0, XMM1); XMM4 = _mm_add_ps(XMM4, XMM5); _mm_storel_pi((__m64*)(w2+i ), XMM0); _mm_storeh_pi((__m64*)(w2+j ), XMM0); _mm_storel_pi((__m64*)(w2+i+2), XMM4); _mm_storeh_pi((__m64*)(w2+j-2), XMM4); x0 += 8; x1 -= 8; T += 16; } #ifdef __INTEL_COMPILER #pragma warning(default : 592) #endif mdct_butterflies_sse(mdct, w2, n2); mdct->mdct_bitreverse(mdct, w); /* roatate + window */ T = mdct->trig_forward+n; x0 =out +n2; for (i = 0; i < n4; i += 4) { __m128 XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7; x0 -= 4; XMM0 = _mm_load_ps(w+4); XMM4 = _mm_load_ps(w ); XMM2 = XMM0; XMM1 = _mm_load_ps(T ); XMM3 = _mm_load_ps(T+ 4); XMM6 = _mm_load_ps(T+ 8); XMM7 = _mm_load_ps(T+12); XMM0 = _mm_shuffle_ps(XMM0, XMM4,_MM_SHUFFLE(0,2,0,2)); XMM2 = _mm_shuffle_ps(XMM2, XMM4,_MM_SHUFFLE(1,3,1,3)); XMM4 = XMM0; XMM5 = XMM2; XMM0 = _mm_mul_ps(XMM0, XMM1); XMM2 = _mm_mul_ps(XMM2, XMM3); XMM4 = _mm_shuffle_ps(XMM4, XMM4, _MM_SHUFFLE(0,1,2,3)); XMM5 = _mm_shuffle_ps(XMM5, XMM5, _MM_SHUFFLE(0,1,2,3)); XMM4 = _mm_mul_ps(XMM4, XMM6); XMM5 = _mm_mul_ps(XMM5, XMM7); XMM0 = _mm_sub_ps(XMM0, XMM2); XMM4 = _mm_add_ps(XMM4, XMM5); _mm_store_ps(x0 , XMM0); _mm_store_ps(out +i, XMM4); w += 8; T += 16; } } void mdct_512_sse(A52ThreadContext *tctx, FLOAT *out, FLOAT *in) { mdct_sse(&tctx->mdct_tctx_512, out, in); } void mdct_256_sse(A52ThreadContext *tctx, FLOAT *out, FLOAT *in) { FLOAT *coef_a, *coef_b, *xx; int i, j; coef_a = in; coef_b = &in[128]; xx = tctx->mdct_tctx_256.buffer1; memcpy(xx, in+64, 192 * sizeof(FLOAT)); xx += 192; for (i = 0; i < 64; i += 4) { __m128 XMM0 = _mm_load_ps(in + i); XMM0 = _mm_xor_ps(XMM0, PCS_RRRR.v); _mm_store_ps(xx + i, XMM0); } xx -= 192; mdct_sse(&tctx->mdct_tctx_256, coef_a, xx); in += 256 + 192; for (i = 0; i < 64; i += 4) { __m128 XMM0 = _mm_load_ps(in + i); XMM0 = _mm_xor_ps(XMM0, PCS_RRRR.v); _mm_store_ps(xx + i, XMM0); } in -= 256 + 192; memcpy(xx+64, in+256, 128 * sizeof(FLOAT)); xx += 192; in += 256 + 128; for (i = 0; i < 64; i += 4) { __m128 XMM0 = _mm_load_ps(in + i); XMM0 = _mm_xor_ps(XMM0, PCS_RRRR.v); _mm_store_ps(xx + i, XMM0); } xx -= 192; in -= 256 + 128; mdct_sse(&tctx->mdct_tctx_256, coef_b, xx); for (i = 0, j = 0; i < 128; i += 4, j += 8) { __m128 XMM0 = _mm_load_ps(coef_a + i); __m128 XMM1 = _mm_load_ps(coef_b + i); __m128 XMM2 = _mm_unpacklo_ps(XMM0, XMM1); __m128 XMM3 = _mm_unpackhi_ps(XMM0, XMM1); _mm_store_ps(out + j , XMM2); _mm_store_ps(out + j+4, XMM3); } } void mdct_ctx_init_sse(MDCTContext *mdct, int n) { mdct_ctx_init(mdct, n); { __m128 pscalem = _mm_set_ps1(mdct->scale); float *T, *S; int n2 = n>>1; int n4 = n>>2; int n8 = n>>3; int i, j; /* for mdct_bitreverse */ T = aligned_malloc(sizeof(*T)*n2); mdct->trig_bitreverse = T; S = mdct->trig+n; for (i = 0; i < n4; i += 8) { __m128 XMM0 = _mm_load_ps(S+i ); __m128 XMM1 = _mm_load_ps(S+i+ 4); __m128 XMM2 = XMM0; __m128 XMM3 = XMM1; XMM2 = _mm_shuffle_ps(XMM2, XMM2, _MM_SHUFFLE(2,3,0,1)); XMM3 = _mm_shuffle_ps(XMM3, XMM3, _MM_SHUFFLE(2,3,0,1)); XMM2 = _mm_xor_ps(XMM2, PCS_RNRN.v); XMM3 = _mm_xor_ps(XMM3, PCS_RNRN.v); _mm_store_ps(T+i*2 , XMM0); _mm_store_ps(T+i*2+ 4, XMM2); _mm_store_ps(T+i*2+ 8, XMM1); _mm_store_ps(T+i*2+12, XMM3); } /* for mdct_forward part 0 */ T = aligned_malloc(sizeof(*T)*(n*2)); mdct->trig_forward = T; S = mdct->trig; for (i = 0, j = n2-4; i < n8; i += 4, j -= 4) { __m128 XMM0 = _mm_load_ps(S+i); __m128 XMM2 = _mm_load_ps(S+j); __m128 XMM1 = _mm_shuffle_ps(XMM2, XMM0, _MM_SHUFFLE(1,0,3,2)); __m128 XMM3 = _mm_shuffle_ps(XMM2, XMM0, _MM_SHUFFLE(3,2,1,0)); XMM0 = _mm_shuffle_ps(XMM1, XMM1, _MM_SHUFFLE(2,3,0,1)); XMM2 = _mm_shuffle_ps(XMM3, XMM3, _MM_SHUFFLE(2,3,0,1)); XMM0 = _mm_xor_ps(XMM0, PCS_RRNN.v); XMM1 = _mm_xor_ps(XMM1, PCS_RNNR.v); XMM2 = _mm_xor_ps(XMM2, PCS_RRNN.v); XMM3 = _mm_xor_ps(XMM3, PCS_RNNR.v); _mm_store_ps(T+i*4 , XMM0); _mm_store_ps(T+i*4+ 4, XMM1); _mm_store_ps(T+i*4+ 8, XMM2); _mm_store_ps(T+i*4+12, XMM3); } for (; i < n4; i += 4, j -= 4) { __m128 XMM0 = _mm_load_ps(S+i); __m128 XMM2 = _mm_load_ps(S+j); __m128 XMM1 = _mm_shuffle_ps(XMM2, XMM0, _MM_SHUFFLE(1,0,3,2)); __m128 XMM3 = _mm_shuffle_ps(XMM2, XMM0, _MM_SHUFFLE(3,2,1,0)); XMM0 = _mm_shuffle_ps(XMM1, XMM1, _MM_SHUFFLE(2,3,0,1)); XMM2 = _mm_shuffle_ps(XMM3, XMM3, _MM_SHUFFLE(2,3,0,1)); XMM0 = _mm_xor_ps(XMM0, PCS_NNRR.v); XMM2 = _mm_xor_ps(XMM2, PCS_NNRR.v); XMM1 = _mm_xor_ps(XMM1, PCS_RNNR.v); XMM3 = _mm_xor_ps(XMM3, PCS_RNNR.v); _mm_store_ps(T+i*4 , XMM0); _mm_store_ps(T+i*4+ 4, XMM1); _mm_store_ps(T+i*4+ 8, XMM2); _mm_store_ps(T+i*4+12, XMM3); } /* for mdct_forward part 1 */ T = mdct->trig_forward+n; S = mdct->trig+n2; for (i = 0; i < n4; i += 4) { __m128 XMM0, XMM1, XMM2; XMM0 = _mm_load_ps(S+4); XMM2 = _mm_load_ps(S ); XMM1 = XMM0; XMM0 = _mm_shuffle_ps(XMM0, XMM2,_MM_SHUFFLE(1,3,1,3)); XMM1 = _mm_shuffle_ps(XMM1, XMM2,_MM_SHUFFLE(0,2,0,2)); XMM0 = _mm_mul_ps(XMM0, pscalem); XMM1 = _mm_mul_ps(XMM1, pscalem); _mm_store_ps(T , XMM0); _mm_store_ps(T+ 4, XMM1); XMM1 = _mm_shuffle_ps(XMM1, XMM1, _MM_SHUFFLE(0,1,2,3)); XMM0 = _mm_shuffle_ps(XMM0, XMM0, _MM_SHUFFLE(0,1,2,3)); _mm_store_ps(T+ 8, XMM1); _mm_store_ps(T+12, XMM0); S += 8; T += 16; } /* for mdct_butterfly_first */ S = mdct->trig; T = aligned_malloc(sizeof(*T)*n*2); mdct->trig_butterfly_first = T; for (i = 0; i < n4; i += 4) { __m128 XMM0, XMM1, XMM2, XMM3, XMM4, XMM5; XMM2 = _mm_load_ps(S ); XMM0 = _mm_load_ps(S+ 4); XMM5 = _mm_load_ps(S+ 8); XMM3 = _mm_load_ps(S+12); XMM1 = XMM0; XMM4 = XMM3; XMM0 = _mm_shuffle_ps(XMM0, XMM2, _MM_SHUFFLE(0,1,0,1)); XMM1 = _mm_shuffle_ps(XMM1, XMM2, _MM_SHUFFLE(1,0,1,0)); XMM3 = _mm_shuffle_ps(XMM3, XMM5, _MM_SHUFFLE(0,1,0,1)); XMM4 = _mm_shuffle_ps(XMM4, XMM5, _MM_SHUFFLE(1,0,1,0)); XMM1 = _mm_xor_ps(XMM1, PCS_RNRN.v); XMM4 = _mm_xor_ps(XMM4, PCS_RNRN.v); _mm_store_ps(T , XMM1); _mm_store_ps(T+ 4, XMM4); _mm_store_ps(T+ 8, XMM0); _mm_store_ps(T+12, XMM3); XMM1 = _mm_xor_ps(XMM1, PCS_RRRR.v); XMM4 = _mm_xor_ps(XMM4, PCS_RRRR.v); XMM0 = _mm_xor_ps(XMM0, PCS_RRRR.v); XMM3 = _mm_xor_ps(XMM3, PCS_RRRR.v); _mm_store_ps(T+n , XMM1); _mm_store_ps(T+n+ 4, XMM4); _mm_store_ps(T+n+ 8, XMM0); _mm_store_ps(T+n+12, XMM3); S += 16; T += 16; } /* for mdct_butterfly_generic(trigint=8) */ S = mdct->trig; T = aligned_malloc(sizeof(*T)*n2); mdct->trig_butterfly_generic8 = T; for (i = 0; i < n; i += 32) { __m128 XMM0, XMM1, XMM2, XMM3, XMM4, XMM5; XMM0 = _mm_load_ps(S+ 24); XMM2 = _mm_load_ps(S+ 16); XMM3 = _mm_load_ps(S+ 8); XMM5 = _mm_load_ps(S ); XMM1 = XMM0; XMM4 = XMM3; XMM0 = _mm_shuffle_ps(XMM0, XMM2, _MM_SHUFFLE(0,1,0,1)); XMM1 = _mm_shuffle_ps(XMM1, XMM2, _MM_SHUFFLE(1,0,1,0)); XMM3 = _mm_shuffle_ps(XMM3, XMM5, _MM_SHUFFLE(0,1,0,1)); XMM4 = _mm_shuffle_ps(XMM4, XMM5, _MM_SHUFFLE(1,0,1,0)); XMM1 = _mm_xor_ps(XMM1, PCS_RNRN.v); XMM4 = _mm_xor_ps(XMM4, PCS_RNRN.v); _mm_store_ps(T , XMM0); _mm_store_ps(T+ 4, XMM1); _mm_store_ps(T+ 8, XMM3); _mm_store_ps(T+12, XMM4); S += 32; T += 16; } /* for mdct_butterfly_generic(trigint=16) */ S = mdct->trig; T = aligned_malloc(sizeof(*T)*n4); mdct->trig_butterfly_generic16 = T; for (i = 0; i < n; i += 64) { __m128 XMM0, XMM1, XMM2, XMM3, XMM4, XMM5; XMM0 = _mm_load_ps(S+ 48); XMM2 = _mm_load_ps(S+ 32); XMM3 = _mm_load_ps(S+ 16); XMM5 = _mm_load_ps(S ); XMM1 = XMM0; XMM4 = XMM3; XMM0 = _mm_shuffle_ps(XMM0, XMM2, _MM_SHUFFLE(0,1,0,1)); XMM1 = _mm_shuffle_ps(XMM1, XMM2, _MM_SHUFFLE(1,0,1,0)); XMM3 = _mm_shuffle_ps(XMM3, XMM5, _MM_SHUFFLE(0,1,0,1)); XMM4 = _mm_shuffle_ps(XMM4, XMM5, _MM_SHUFFLE(1,0,1,0)); XMM1 = _mm_xor_ps(XMM1, PCS_RNRN.v); XMM4 = _mm_xor_ps(XMM4, PCS_RNRN.v); _mm_store_ps(T , XMM0); _mm_store_ps(T+ 4, XMM1); _mm_store_ps(T+ 8, XMM3); _mm_store_ps(T+12, XMM4); S += 64; T += 16; } /* for mdct_butterfly_generic(trigint=32) */ if (n < 128) { mdct->trig_butterfly_generic32 = NULL; } else { S = mdct->trig; T = aligned_malloc(sizeof(*T)*n8); mdct->trig_butterfly_generic32 = T; for (i = 0; i < n; i += 128) { __m128 XMM0, XMM1, XMM2, XMM3, XMM4, XMM5; XMM0 = _mm_load_ps(S+ 96); XMM2 = _mm_load_ps(S+ 64); XMM3 = _mm_load_ps(S+ 32); XMM5 = _mm_load_ps(S ); XMM1 = XMM0; XMM4 = XMM3; XMM0 = _mm_shuffle_ps(XMM0, XMM2, _MM_SHUFFLE(0,1,0,1)); XMM1 = _mm_shuffle_ps(XMM1, XMM2, _MM_SHUFFLE(1,0,1,0)); XMM3 = _mm_shuffle_ps(XMM3, XMM5, _MM_SHUFFLE(0,1,0,1)); XMM4 = _mm_shuffle_ps(XMM4, XMM5, _MM_SHUFFLE(1,0,1,0)); XMM1 = _mm_xor_ps(XMM1, PCS_RNRN.v); XMM4 = _mm_xor_ps(XMM4, PCS_RNRN.v); _mm_store_ps(T , XMM0); _mm_store_ps(T+ 4, XMM1); _mm_store_ps(T+ 8, XMM3); _mm_store_ps(T+12, XMM4); S += 128; T += 16; } } /* for mdct_butterfly_generic(trigint=64) */ if (n < 256) { mdct->trig_butterfly_generic64 = NULL; } else { S = mdct->trig; T = aligned_malloc(sizeof(*T)*(n8>>1)); mdct->trig_butterfly_generic64 = T; for (i = 0; i < n; i += 256) { __m128 XMM0, XMM1, XMM2, XMM3, XMM4, XMM5; XMM0 = _mm_load_ps(S+192); XMM2 = _mm_load_ps(S+128); XMM3 = _mm_load_ps(S+ 64); XMM5 = _mm_load_ps(S ); XMM1 = XMM0; XMM4 = XMM3; XMM0 = _mm_shuffle_ps(XMM0, XMM2, _MM_SHUFFLE(0,1,0,1)); XMM1 = _mm_shuffle_ps(XMM1, XMM2, _MM_SHUFFLE(1,0,1,0)); XMM3 = _mm_shuffle_ps(XMM3, XMM5, _MM_SHUFFLE(0,1,0,1)); XMM4 = _mm_shuffle_ps(XMM4, XMM5, _MM_SHUFFLE(1,0,1,0)); XMM1 = _mm_xor_ps(XMM1, PCS_RNRN.v); XMM4 = _mm_xor_ps(XMM4, PCS_RNRN.v); _mm_store_ps(T , XMM0); _mm_store_ps(T+ 4, XMM1); _mm_store_ps(T+ 8, XMM3); _mm_store_ps(T+12, XMM4); S += 256; T += 16; } } } } aften/libaften/x86/mdct_common_sse.h000066400000000000000000000041741132016273200177110ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * * SSE MDCT functions * This file is derived from libvorbis lancer patch * Copyright (c) 2006-2007 prakash@punnoor.de * Copyright (c) 2006, blacksword8192@hotmail.com * Copyright (c) 2002, 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. */ /** * @file x86/mdct_common_sse.h * MDCT SSE common header */ #ifndef MDCT_COMMON_SSE_H #define MDCT_COMMON_SSE_H #include "libaften/mdct.h" void mdct_butterfly_16_sse(FLOAT *x); void mdct_512_sse(struct A52ThreadContext *tctx, FLOAT *out, FLOAT *in); void mdct_256_sse(struct A52ThreadContext *tctx, FLOAT *out, FLOAT *in); void mdct_ctx_init_sse(MDCTContext *mdct, int n); #endif /* MDCT_COMMON_SSE_H */ aften/libaften/x86/mdct_sse.c000066400000000000000000000333221132016273200163310ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * * SSE MDCT functions * This file is derived from libvorbis lancer patch * Copyright (c) 2006-2007 prakash@punnoor.de * Copyright (c) 2006, blacksword8192@hotmail.com * Copyright (c) 2002, 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. */ /** * @file x86/mdct_sse.c * MDCT, optimized for the SSE instruction set */ #include "a52enc.h" #include "x86/simd_support.h" #include "mdct_common_sse.h" static const union __m128ui PCS_RNRN = {{0x00000000, 0x80000000, 0x00000000, 0x80000000}}; static const union __m128f PFV_0P5 = {{0.5f, 0.5f, 0.5f, 0.5f}}; /** 32 point butterfly (in place, 4 register) */ static void mdct_butterfly_32_sse(FLOAT *x) { static _MM_ALIGN16 const float PFV0[4] = { -AFT_PI3_8, -AFT_PI1_8, -AFT_PI2_8, -AFT_PI2_8 }; static _MM_ALIGN16 const float PFV1[4] = { -AFT_PI1_8, AFT_PI3_8, -AFT_PI2_8, AFT_PI2_8 }; static _MM_ALIGN16 const float PFV2[4] = { -AFT_PI1_8, -AFT_PI3_8, -1.f, 1.f }; static _MM_ALIGN16 const float PFV3[4] = { -AFT_PI3_8, AFT_PI1_8, 0.f, 0.f }; static _MM_ALIGN16 const float PFV4[4] = { AFT_PI3_8, AFT_PI3_8, AFT_PI2_8, AFT_PI2_8 }; static _MM_ALIGN16 const float PFV5[4] = { -AFT_PI1_8, AFT_PI1_8, -AFT_PI2_8, AFT_PI2_8 }; static _MM_ALIGN16 const float PFV6[4] = { AFT_PI1_8, AFT_PI3_8, 1.f, 1.f }; static _MM_ALIGN16 const float PFV7[4] = { -AFT_PI3_8, AFT_PI1_8, 0.f, 0.f }; __m128 XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7; XMM0 = _mm_load_ps(x+16); XMM1 = _mm_load_ps(x+20); XMM2 = _mm_load_ps(x+24); XMM3 = _mm_load_ps(x+28); XMM4 = XMM0; XMM5 = XMM1; XMM6 = XMM2; XMM7 = XMM3; XMM0 = _mm_sub_ps(XMM0, PM128(x )); XMM1 = _mm_sub_ps(XMM1, PM128(x+ 4)); XMM2 = _mm_sub_ps(XMM2, PM128(x+ 8)); XMM3 = _mm_sub_ps(XMM3, PM128(x+12)); XMM4 = _mm_add_ps(XMM4, PM128(x )); XMM5 = _mm_add_ps(XMM5, PM128(x+ 4)); XMM6 = _mm_add_ps(XMM6, PM128(x+ 8)); XMM7 = _mm_add_ps(XMM7, PM128(x+12)); _mm_store_ps(x+16, XMM4); _mm_store_ps(x+20, XMM5); _mm_store_ps(x+24, XMM6); _mm_store_ps(x+28, XMM7); XMM4 = XMM0; XMM5 = XMM1; XMM6 = XMM2; XMM7 = XMM3; XMM0 = _mm_shuffle_ps(XMM0, XMM0, _MM_SHUFFLE(3,3,1,1)); XMM4 = _mm_shuffle_ps(XMM4, XMM4, _MM_SHUFFLE(2,2,0,0)); XMM1 = _mm_shuffle_ps(XMM1, XMM1, _MM_SHUFFLE(2,3,1,1)); XMM5 = _mm_shuffle_ps(XMM5, XMM5, _MM_SHUFFLE(2,3,0,0)); XMM2 = _mm_shuffle_ps(XMM2, XMM2, _MM_SHUFFLE(2,2,1,0)); XMM6 = _mm_shuffle_ps(XMM6, XMM6, _MM_SHUFFLE(3,3,0,1)); XMM3 = _mm_shuffle_ps(XMM3, XMM3, _MM_SHUFFLE(3,2,0,0)); XMM7 = _mm_shuffle_ps(XMM7, XMM7, _MM_SHUFFLE(3,2,1,1)); XMM0 = _mm_mul_ps(XMM0, PM128(PFV0)); XMM4 = _mm_mul_ps(XMM4, PM128(PFV1)); XMM1 = _mm_mul_ps(XMM1, PM128(PFV2)); XMM5 = _mm_mul_ps(XMM5, PM128(PFV3)); XMM2 = _mm_mul_ps(XMM2, PM128(PFV4)); XMM6 = _mm_mul_ps(XMM6, PM128(PFV5)); XMM3 = _mm_mul_ps(XMM3, PM128(PFV6)); XMM7 = _mm_mul_ps(XMM7, PM128(PFV7)); XMM0 = _mm_add_ps(XMM0, XMM4); XMM1 = _mm_add_ps(XMM1, XMM5); XMM2 = _mm_add_ps(XMM2, XMM6); XMM3 = _mm_add_ps(XMM3, XMM7); _mm_store_ps(x , XMM0); _mm_store_ps(x+ 4, XMM1); _mm_store_ps(x+ 8, XMM2); _mm_store_ps(x+12, XMM3); mdct_butterfly_16_sse(x); mdct_butterfly_16_sse(x+16); } /** N point first stage butterfly (in place, 2 register) */ static void mdct_butterfly_first_sse(FLOAT *trig, FLOAT *x, int points) { float *X1 = x + points - 8; float *X2 = x + (points>>1) - 8; do { __m128 XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7; XMM0 = _mm_load_ps(X1+4); XMM1 = _mm_load_ps(X1 ); XMM2 = _mm_load_ps(X2+4); XMM3 = _mm_load_ps(X2 ); XMM4 = XMM0; XMM5 = XMM1; XMM0 = _mm_sub_ps(XMM0, XMM2); XMM1 = _mm_sub_ps(XMM1, XMM3); XMM4 = _mm_add_ps(XMM4, XMM2); XMM5 = _mm_add_ps(XMM5, XMM3); XMM2 = XMM0; XMM3 = XMM1; _mm_store_ps(X1+4, XMM4); _mm_store_ps(X1 , XMM5); XMM0 = _mm_shuffle_ps(XMM0 , XMM0 , _MM_SHUFFLE(3,3,1,1)); XMM1 = _mm_shuffle_ps(XMM1 , XMM1 , _MM_SHUFFLE(3,3,1,1)); XMM2 = _mm_shuffle_ps(XMM2 , XMM2 , _MM_SHUFFLE(2,2,0,0)); XMM3 = _mm_shuffle_ps(XMM3 , XMM3 , _MM_SHUFFLE(2,2,0,0)); XMM4 = _mm_load_ps(trig ); XMM5 = _mm_load_ps(trig+ 4); XMM6 = _mm_load_ps(trig+ 8); XMM7 = _mm_load_ps(trig+12); XMM2 = _mm_mul_ps(XMM2, XMM4); XMM3 = _mm_mul_ps(XMM3, XMM5); XMM0 = _mm_mul_ps(XMM0, XMM6); XMM1 = _mm_mul_ps(XMM1, XMM7); XMM0 = _mm_add_ps(XMM0, XMM2); XMM1 = _mm_add_ps(XMM1, XMM3); _mm_store_ps(X2+4, XMM0); _mm_store_ps(X2 , XMM1); X1 -= 8; X2 -= 8; trig+= 16; } while (X2 >= x); } /** N/stage point generic N stage butterfly (in place, 2 register) */ static void mdct_butterfly_generic_sse(MDCTContext *mdct, FLOAT *x, int points, int trigint) { float *T; float *x1 = x + points - 8; float *x2 = x + (points>>1) - 8; switch (trigint) { default : T = mdct->trig; do { __m128 XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6; XMM0 = _mm_load_ps(x1 ); XMM1 = _mm_load_ps(x2 ); XMM2 = _mm_load_ps(x1+4); XMM3 = _mm_load_ps(x2+4); XMM4 = XMM0; XMM5 = XMM2; XMM0 = _mm_sub_ps(XMM0, XMM1); XMM2 = _mm_sub_ps(XMM2, XMM3); XMM4 = _mm_add_ps(XMM4, XMM1); XMM5 = _mm_add_ps(XMM5, XMM3); XMM1 = XMM0; XMM3 = XMM2; _mm_store_ps(x1 , XMM4); _mm_store_ps(x1+4, XMM5); XMM0 = _mm_shuffle_ps(XMM0, XMM0, _MM_SHUFFLE(3,3,1,1)); XMM1 = _mm_shuffle_ps(XMM1, XMM1, _MM_SHUFFLE(2,2,0,0)); XMM2 = _mm_shuffle_ps(XMM2, XMM2, _MM_SHUFFLE(3,3,1,1)); XMM3 = _mm_shuffle_ps(XMM3, XMM3, _MM_SHUFFLE(2,2,0,0)); XMM4 = _mm_load_ps(T+trigint*3); XMM5 = _mm_load_ps(T+trigint*3); XMM6 = _mm_load_ps(T+trigint*2); XMM1 = _mm_xor_ps(XMM1, PCS_RNRN.v); XMM4 = _mm_shuffle_ps(XMM4, XMM6, _MM_SHUFFLE(0,1,0,1)); XMM5 = _mm_shuffle_ps(XMM5, XMM6, _MM_SHUFFLE(1,0,1,0)); XMM0 = _mm_mul_ps(XMM0, XMM4); XMM1 = _mm_mul_ps(XMM1, XMM5); XMM4 = _mm_load_ps(T+trigint ); XMM5 = _mm_load_ps(T+trigint ); XMM6 = _mm_load_ps(T ); XMM3 = _mm_xor_ps(XMM3, PCS_RNRN.v); XMM4 = _mm_shuffle_ps(XMM4, XMM6, _MM_SHUFFLE(0,1,0,1)); XMM5 = _mm_shuffle_ps(XMM5, XMM6, _MM_SHUFFLE(1,0,1,0)); XMM2 = _mm_mul_ps(XMM2, XMM4); XMM3 = _mm_mul_ps(XMM3, XMM5); XMM0 = _mm_add_ps(XMM0, XMM1); XMM2 = _mm_add_ps(XMM2, XMM3); _mm_store_ps(x2 , XMM0); _mm_store_ps(x2+4, XMM2); T += trigint*4; x1 -= 8; x2 -= 8; } while (x2>=x); return; case 8: T = mdct->trig_butterfly_generic8; break; case 16: T = mdct->trig_butterfly_generic16; break; case 32: T = mdct->trig_butterfly_generic32; break; case 64: T = mdct->trig_butterfly_generic64; break; } _mm_prefetch((char*)T , _MM_HINT_NTA); do { __m128 XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7; _mm_prefetch((char*)(T+16), _MM_HINT_NTA); XMM0 = _mm_load_ps(x1 ); XMM1 = _mm_load_ps(x2 ); XMM2 = _mm_load_ps(x1+4); XMM3 = _mm_load_ps(x2+4); XMM4 = XMM0; XMM5 = XMM2; XMM0 = _mm_sub_ps(XMM0, XMM1); XMM2 = _mm_sub_ps(XMM2, XMM3); XMM4 = _mm_add_ps(XMM4, XMM1); XMM5 = _mm_add_ps(XMM5, XMM3); XMM1 = XMM0; XMM3 = XMM2; XMM0 = _mm_shuffle_ps(XMM0, XMM0, _MM_SHUFFLE(3,3,1,1)); XMM1 = _mm_shuffle_ps(XMM1, XMM1, _MM_SHUFFLE(2,2,0,0)); _mm_store_ps(x1 , XMM4); _mm_store_ps(x1+4, XMM5); XMM2 = _mm_shuffle_ps(XMM2, XMM2, _MM_SHUFFLE(3,3,1,1)); XMM3 = _mm_shuffle_ps(XMM3, XMM3, _MM_SHUFFLE(2,2,0,0)); XMM4 = _mm_load_ps(T ); XMM5 = _mm_load_ps(T+ 4); XMM6 = _mm_load_ps(T+ 8); XMM7 = _mm_load_ps(T+12); XMM0 = _mm_mul_ps(XMM0, XMM4); XMM1 = _mm_mul_ps(XMM1, XMM5); XMM2 = _mm_mul_ps(XMM2, XMM6); XMM3 = _mm_mul_ps(XMM3, XMM7); XMM0 = _mm_add_ps(XMM0, XMM1); XMM2 = _mm_add_ps(XMM2, XMM3); _mm_store_ps(x2 , XMM0); _mm_store_ps(x2+4, XMM2); T += 16; x1 -= 8; x2 -= 8; } while (x2 >= x); } static void mdct_bitreverse_sse(MDCTContext *mdct, FLOAT *x) { int n = mdct->n; int *bit = mdct->bitrev; float *w0 = x; float *w1 = x = w0+(n>>1); float *T = mdct->trig_bitreverse; do { float *x0 = x+bit[0]; float *x1 = x+bit[1]; float *x2 = x+bit[2]; float *x3 = x+bit[3]; __m128 XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7; w1 -= 4; XMM0 = _mm_lddqu_ps(x0); XMM1 = _mm_lddqu_ps(x1); XMM4 = _mm_lddqu_ps(x2); XMM7 = _mm_lddqu_ps(x3); XMM2 = XMM0; XMM3 = XMM1; XMM5 = XMM0; XMM6 = XMM1; XMM0 = _mm_shuffle_ps(XMM0, XMM4, _MM_SHUFFLE(0,1,0,1)); XMM1 = _mm_shuffle_ps(XMM1, XMM7, _MM_SHUFFLE(0,1,0,1)); XMM2 = _mm_shuffle_ps(XMM2, XMM4, _MM_SHUFFLE(0,0,0,0)); XMM3 = _mm_shuffle_ps(XMM3, XMM7, _MM_SHUFFLE(0,0,0,0)); XMM5 = _mm_shuffle_ps(XMM5, XMM4, _MM_SHUFFLE(1,1,1,1)); XMM6 = _mm_shuffle_ps(XMM6, XMM7, _MM_SHUFFLE(1,1,1,1)); XMM4 = _mm_load_ps(T ); XMM7 = _mm_load_ps(T+4); XMM1 = _mm_xor_ps(XMM1, PCS_RNRN.v); XMM2 = _mm_add_ps(XMM2, XMM3); XMM5 = _mm_sub_ps(XMM5, XMM6); XMM0 = _mm_add_ps(XMM0, XMM1); XMM2 = _mm_mul_ps(XMM2, XMM4); XMM5 = _mm_mul_ps(XMM5, XMM7); XMM0 = _mm_mul_ps(XMM0, PFV_0P5.v); XMM2 = _mm_add_ps(XMM2, XMM5); XMM1 = XMM0; XMM3 = XMM2; XMM1 = _mm_xor_ps(XMM1, PCS_RNRN.v); XMM3 = _mm_xor_ps(XMM3, PCS_RNRN.v); XMM0 = _mm_add_ps(XMM0, XMM2); XMM1 = _mm_sub_ps(XMM1, XMM3); _mm_store_ps(w0, XMM0); _mm_storeh_pi((__m64*)(w1 ), XMM1); _mm_storel_pi((__m64*)(w1+2), XMM1); T += 8; bit += 4; w0 += 4; } while (w0 < w1); } void mdct_init_sse(A52Context *ctx) { mdct_ctx_init_sse(&ctx->mdct_ctx_512, 512); mdct_ctx_init_sse(&ctx->mdct_ctx_256, 256); ctx->mdct_ctx_512.mdct = mdct_512_sse; ctx->mdct_ctx_512.mdct_bitreverse = mdct_bitreverse_sse; ctx->mdct_ctx_512.mdct_butterfly_generic = mdct_butterfly_generic_sse; ctx->mdct_ctx_512.mdct_butterfly_first = mdct_butterfly_first_sse; ctx->mdct_ctx_512.mdct_butterfly_32 = mdct_butterfly_32_sse; ctx->mdct_ctx_256.mdct = mdct_256_sse; ctx->mdct_ctx_256.mdct_bitreverse = mdct_bitreverse_sse; ctx->mdct_ctx_256.mdct_butterfly_generic = mdct_butterfly_generic_sse; ctx->mdct_ctx_256.mdct_butterfly_first = mdct_butterfly_first_sse; ctx->mdct_ctx_256.mdct_butterfly_32 = mdct_butterfly_32_sse; } aften/libaften/x86/mdct_sse3.c000066400000000000000000000321631132016273200164160ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * * SSE3 MDCT functions * This file is derived from libvorbis lancer patch * Copyright (c) 2006-2007 prakash@punnoor.de * Copyright (c) 2006, blacksword8192@hotmail.com * Copyright (c) 2002, 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. */ /** * @file x86/mdct_sse.c * MDCT file, optimized for the SSE3 instruction set */ #include "a52enc.h" #include "x86/simd_support.h" #include "mdct_common_sse.h" static const union __m128ui PCS_RNRN = {{0x00000000, 0x80000000, 0x00000000, 0x80000000}}; static const union __m128f PFV_0P5 = {{0.5f, 0.5f, 0.5f, 0.5f}}; /** 32 point butterfly */ static void mdct_butterfly_32_sse3(FLOAT *x) { static _MM_ALIGN16 const float PFV0[4] = { -AFT_PI3_8, -AFT_PI1_8, -AFT_PI2_8, -AFT_PI2_8 }; static _MM_ALIGN16 const float PFV1[4] = { -AFT_PI1_8, AFT_PI3_8, -AFT_PI2_8, AFT_PI2_8 }; static _MM_ALIGN16 const float PFV2[4] = { -AFT_PI1_8, -AFT_PI3_8, -1.f, 1.f }; static _MM_ALIGN16 const float PFV3[4] = { -AFT_PI3_8, AFT_PI1_8, 0.f, 0.f }; static _MM_ALIGN16 const float PFV4[4] = { AFT_PI3_8, AFT_PI3_8, AFT_PI2_8, AFT_PI2_8 }; static _MM_ALIGN16 const float PFV5[4] = { -AFT_PI1_8, AFT_PI1_8, -AFT_PI2_8, AFT_PI2_8 }; static _MM_ALIGN16 const float PFV6[4] = { AFT_PI1_8, AFT_PI3_8, 1.f, 1.f }; static _MM_ALIGN16 const float PFV7[4] = { -AFT_PI3_8, AFT_PI1_8, 0.f, 0.f }; __m128 XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7; XMM0 = _mm_load_ps(x+16); XMM1 = _mm_load_ps(x+20); XMM2 = _mm_load_ps(x+24); XMM3 = _mm_load_ps(x+28); XMM4 = XMM0; XMM5 = XMM1; XMM6 = XMM2; XMM7 = XMM3; XMM0 = _mm_sub_ps(XMM0, PM128(x )); XMM1 = _mm_sub_ps(XMM1, PM128(x+ 4)); XMM2 = _mm_sub_ps(XMM2, PM128(x+ 8)); XMM3 = _mm_sub_ps(XMM3, PM128(x+12)); XMM4 = _mm_add_ps(XMM4, PM128(x )); XMM5 = _mm_add_ps(XMM5, PM128(x+ 4)); XMM6 = _mm_add_ps(XMM6, PM128(x+ 8)); XMM7 = _mm_add_ps(XMM7, PM128(x+12)); _mm_store_ps(x+16, XMM4); _mm_store_ps(x+20, XMM5); _mm_store_ps(x+24, XMM6); _mm_store_ps(x+28, XMM7); XMM4 = _mm_moveldup_ps(XMM0); XMM5 = XMM1; XMM0 = _mm_movehdup_ps(XMM0); XMM6 = XMM2; XMM7 = XMM3; XMM1 = _mm_shuffle_ps(XMM1, XMM1, _MM_SHUFFLE(2,3,1,1)); XMM5 = _mm_shuffle_ps(XMM5, XMM5, _MM_SHUFFLE(2,3,0,0)); XMM2 = _mm_shuffle_ps(XMM2, XMM2, _MM_SHUFFLE(2,2,1,0)); XMM6 = _mm_shuffle_ps(XMM6, XMM6, _MM_SHUFFLE(3,3,0,1)); XMM3 = _mm_shuffle_ps(XMM3, XMM3, _MM_SHUFFLE(3,2,0,0)); XMM7 = _mm_shuffle_ps(XMM7, XMM7, _MM_SHUFFLE(3,2,1,1)); XMM0 = _mm_mul_ps(XMM0, PM128(PFV0)); XMM4 = _mm_mul_ps(XMM4, PM128(PFV1)); XMM1 = _mm_mul_ps(XMM1, PM128(PFV2)); XMM5 = _mm_mul_ps(XMM5, PM128(PFV3)); XMM2 = _mm_mul_ps(XMM2, PM128(PFV4)); XMM6 = _mm_mul_ps(XMM6, PM128(PFV5)); XMM3 = _mm_mul_ps(XMM3, PM128(PFV6)); XMM7 = _mm_mul_ps(XMM7, PM128(PFV7)); XMM0 = _mm_add_ps(XMM0, XMM4); XMM1 = _mm_add_ps(XMM1, XMM5); XMM2 = _mm_add_ps(XMM2, XMM6); XMM3 = _mm_add_ps(XMM3, XMM7); _mm_store_ps(x , XMM0); _mm_store_ps(x+ 4, XMM1); _mm_store_ps(x+ 8, XMM2); _mm_store_ps(x+12, XMM3); mdct_butterfly_16_sse(x); mdct_butterfly_16_sse(x+16); } /** N point first stage butterfly */ static void mdct_butterfly_first_sse3(FLOAT *trig, FLOAT *x, int points) { float *X1 = x + points - 8; float *X2 = x + (points>>1) - 8; do { __m128 XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7; XMM0 = _mm_load_ps(X1+4); XMM1 = _mm_load_ps(X1 ); XMM2 = _mm_load_ps(X2+4); XMM3 = _mm_load_ps(X2 ); XMM4 = XMM0; XMM5 = XMM1; XMM0 = _mm_sub_ps(XMM0, XMM2); XMM1 = _mm_sub_ps(XMM1, XMM3); XMM4 = _mm_add_ps(XMM4, XMM2); XMM5 = _mm_add_ps(XMM5, XMM3); XMM2 = _mm_moveldup_ps(XMM0); XMM3 = _mm_moveldup_ps(XMM1); _mm_store_ps(X1+4, XMM4); _mm_store_ps(X1 , XMM5); XMM0 = _mm_movehdup_ps(XMM0); XMM1 = _mm_movehdup_ps(XMM1); XMM4 = _mm_load_ps(trig ); XMM5 = _mm_load_ps(trig+ 4); XMM6 = _mm_load_ps(trig+ 8); XMM7 = _mm_load_ps(trig+12); XMM2 = _mm_mul_ps(XMM2, XMM4); XMM3 = _mm_mul_ps(XMM3, XMM5); XMM0 = _mm_mul_ps(XMM0, XMM6); XMM1 = _mm_mul_ps(XMM1, XMM7); XMM0 = _mm_add_ps(XMM0, XMM2); XMM1 = _mm_add_ps(XMM1, XMM3); _mm_store_ps(X2+4, XMM0); _mm_store_ps(X2 , XMM1); X1 -= 8; X2 -= 8; trig+= 16; } while (X2 >= x); } /** N/stage point generic N stage butterfly */ static void mdct_butterfly_generic_sse3(MDCTContext *mdct, FLOAT *x, int points, int trigint) { float *T; float *x1 = x + points - 8; float *x2 = x + (points>>1) - 8; switch (trigint) { default : T = mdct->trig; do { __m128 XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6; XMM0 = _mm_load_ps(x1 ); XMM1 = _mm_load_ps(x2 ); XMM2 = _mm_load_ps(x1+4); XMM3 = _mm_load_ps(x2+4); XMM4 = XMM0; XMM5 = XMM2; XMM0 = _mm_sub_ps(XMM0, XMM1); XMM2 = _mm_sub_ps(XMM2, XMM3); XMM4 = _mm_add_ps(XMM4, XMM1); XMM5 = _mm_add_ps(XMM5, XMM3); XMM1 = XMM0; XMM3 = XMM2; _mm_store_ps(x1 , XMM4); _mm_store_ps(x1+4, XMM5); XMM0 = _mm_movehdup_ps(XMM0); XMM1 = _mm_moveldup_ps(XMM1); XMM2 = _mm_movehdup_ps(XMM2); XMM3 = _mm_moveldup_ps(XMM3); XMM4 = _mm_load_ps(T+trigint*3); XMM5 = _mm_load_ps(T+trigint*3); XMM6 = _mm_load_ps(T+trigint*2); XMM1 = _mm_xor_ps(XMM1, PCS_RNRN.v); XMM4 = _mm_shuffle_ps(XMM4, XMM6, _MM_SHUFFLE(0,1,0,1)); XMM5 = _mm_shuffle_ps(XMM5, XMM6, _MM_SHUFFLE(1,0,1,0)); XMM0 = _mm_mul_ps(XMM0, XMM4); XMM1 = _mm_mul_ps(XMM1, XMM5); XMM4 = _mm_load_ps(T+trigint ); XMM5 = _mm_load_ps(T+trigint ); XMM6 = _mm_load_ps(T ); XMM3 = _mm_xor_ps(XMM3, PCS_RNRN.v); XMM4 = _mm_shuffle_ps(XMM4, XMM6, _MM_SHUFFLE(0,1,0,1)); XMM5 = _mm_shuffle_ps(XMM5, XMM6, _MM_SHUFFLE(1,0,1,0)); XMM2 = _mm_mul_ps(XMM2, XMM4); XMM3 = _mm_mul_ps(XMM3, XMM5); XMM0 = _mm_add_ps(XMM0, XMM1); XMM2 = _mm_add_ps(XMM2, XMM3); _mm_store_ps(x2 , XMM0); _mm_store_ps(x2+4, XMM2); T += trigint*4; x1 -= 8; x2 -= 8; } while (x2>=x); return; case 8: T = mdct->trig_butterfly_generic8; break; case 16: T = mdct->trig_butterfly_generic16; break; case 32: T = mdct->trig_butterfly_generic32; break; case 64: T = mdct->trig_butterfly_generic64; break; } _mm_prefetch((char*)T , _MM_HINT_NTA); do { __m128 XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7; _mm_prefetch((char*)(T+16), _MM_HINT_NTA); XMM0 = _mm_load_ps(x1 ); XMM1 = _mm_load_ps(x2 ); XMM2 = _mm_load_ps(x1+4); XMM3 = _mm_load_ps(x2+4); XMM4 = XMM0; XMM5 = XMM2; XMM0 = _mm_sub_ps(XMM0, XMM1); XMM2 = _mm_sub_ps(XMM2, XMM3); XMM4 = _mm_add_ps(XMM4, XMM1); XMM5 = _mm_add_ps(XMM5, XMM3); XMM1 = _mm_moveldup_ps(XMM0); XMM3 = _mm_moveldup_ps(XMM2); _mm_store_ps(x1 , XMM4); _mm_store_ps(x1+4, XMM5); XMM0 = _mm_movehdup_ps(XMM0); XMM2 = _mm_movehdup_ps(XMM2); XMM4 = _mm_load_ps(T ); XMM5 = _mm_load_ps(T+ 4); XMM6 = _mm_load_ps(T+ 8); XMM7 = _mm_load_ps(T+12); XMM0 = _mm_mul_ps(XMM0, XMM4); XMM1 = _mm_mul_ps(XMM1, XMM5); XMM2 = _mm_mul_ps(XMM2, XMM6); XMM3 = _mm_mul_ps(XMM3, XMM7); XMM0 = _mm_add_ps(XMM0, XMM1); XMM2 = _mm_add_ps(XMM2, XMM3); _mm_store_ps(x2 , XMM0); _mm_store_ps(x2+4, XMM2); T += 16; x1 -= 8; x2 -= 8; } while (x2 >= x); } static void mdct_bitreverse_sse3(MDCTContext *mdct, FLOAT *x) { int n = mdct->n; int *bit = mdct->bitrev; float *w0 = x; float *w1 = x = w0+(n>>1); float *T = mdct->trig_bitreverse; do { float *x0 = x+bit[0]; float *x1 = x+bit[1]; float *x2 = x+bit[2]; float *x3 = x+bit[3]; __m128 XMM0, XMM1, XMM2, XMM3, XMM4, XMM5, XMM6, XMM7; w1 -= 4; XMM0 = _mm_lddqu_ps(x0); XMM1 = _mm_lddqu_ps(x1); XMM4 = _mm_lddqu_ps(x2); XMM7 = _mm_lddqu_ps(x3); XMM2 = XMM0; XMM3 = XMM1; XMM5 = XMM0; XMM6 = XMM1; XMM0 = _mm_shuffle_ps(XMM0, XMM4, _MM_SHUFFLE(0,1,0,1)); XMM1 = _mm_shuffle_ps(XMM1, XMM7, _MM_SHUFFLE(0,1,0,1)); XMM2 = _mm_shuffle_ps(XMM2, XMM4, _MM_SHUFFLE(0,0,0,0)); XMM3 = _mm_shuffle_ps(XMM3, XMM7, _MM_SHUFFLE(0,0,0,0)); XMM5 = _mm_shuffle_ps(XMM5, XMM4, _MM_SHUFFLE(1,1,1,1)); XMM6 = _mm_shuffle_ps(XMM6, XMM7, _MM_SHUFFLE(1,1,1,1)); XMM4 = _mm_load_ps(T ); XMM7 = _mm_load_ps(T+4); XMM1 = _mm_xor_ps(XMM1, PCS_RNRN.v); XMM2 = _mm_add_ps(XMM2, XMM3); XMM5 = _mm_sub_ps(XMM5, XMM6); XMM0 = _mm_add_ps(XMM0, XMM1); XMM2 = _mm_mul_ps(XMM2, XMM4); XMM5 = _mm_mul_ps(XMM5, XMM7); XMM0 = _mm_mul_ps(XMM0, PFV_0P5.v); XMM2 = _mm_add_ps(XMM2, XMM5); XMM1 = XMM0; XMM3 = XMM2; XMM1 = _mm_xor_ps(XMM1, PCS_RNRN.v); XMM0 = _mm_add_ps(XMM0, XMM2); XMM1 = _mm_addsub_ps(XMM1, XMM3); _mm_store_ps(w0, XMM0); _mm_storeh_pi((__m64*)(w1 ), XMM1); _mm_storel_pi((__m64*)(w1+2), XMM1); T += 8; bit += 4; w0 += 4; } while (w0 < w1); } void mdct_init_sse3(A52Context *ctx) { mdct_ctx_init_sse(&ctx->mdct_ctx_512, 512); mdct_ctx_init_sse(&ctx->mdct_ctx_256, 256); ctx->mdct_ctx_512.mdct = mdct_512_sse; ctx->mdct_ctx_512.mdct_bitreverse = mdct_bitreverse_sse3; ctx->mdct_ctx_512.mdct_butterfly_generic = mdct_butterfly_generic_sse3; ctx->mdct_ctx_512.mdct_butterfly_first = mdct_butterfly_first_sse3; ctx->mdct_ctx_512.mdct_butterfly_32 = mdct_butterfly_32_sse3; ctx->mdct_ctx_256.mdct = mdct_256_sse; ctx->mdct_ctx_256.mdct_bitreverse = mdct_bitreverse_sse3; ctx->mdct_ctx_256.mdct_butterfly_generic = mdct_butterfly_generic_sse3; ctx->mdct_ctx_256.mdct_butterfly_first = mdct_butterfly_first_sse3; ctx->mdct_ctx_256.mdct_butterfly_32 = mdct_butterfly_32_sse3; } aften/libaften/x86/simd_support.h000066400000000000000000000034121132016273200172620ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * * SIMD support header * Copyright (C) 2005-2007 by Prakash Punnoor * prakash@punnoor.de * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; * version 2 of the License * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ #ifndef X86_SIMD_SUPPORT_H #define X86_SIMD_SUPPORT_H #include "mem.h" #ifdef USE_MMX #include union __m64ui { unsigned int ui[4]; __m64 v; }; #ifdef _MSC_VER #pragma warning (disable: 4799) #endif #endif /* USE_MMX */ #ifdef USE_SSE #include union __m128ui { unsigned int ui[4]; __m128 v; }; union __m128f { float f[4]; __m128 v; }; #define _mm_lddqu_ps(x) _mm_loadu_ps(x) #ifdef USE_SSE2 #include union __m128iui { unsigned int ui[4]; __m128i v; }; #ifdef USE_SSE3 #include #ifdef EMU_CASTSI128 #define _mm_castsi128_ps(X) ((__m128)(X)) #endif /* EMU_CASTSI128 */ #undef _mm_lddqu_ps #define _mm_lddqu_ps(x) _mm_castsi128_ps(_mm_lddqu_si128((__m128i*)(x))) #endif /* USE_SSE3 */ #endif /* USE_SSE2 */ #ifndef _MM_ALIGN16 #define _MM_ALIGN16 __attribute__((aligned(16))) #endif #define PM128(x) (*(__m128*)(x)) #endif /* USE_SSE */ #endif /* X86_SIMD_SUPPORT_H */ aften/libaften/x86/window.h000066400000000000000000000020311132016273200160350ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * * x86 window functions header * Copyright (C) 2007 by Prakash Punnoor * prakash@punnoor.de * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; * version 2 of the License * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ /** * @file window.h * A/52 Kaiser-Bessel Derived Window x86 header */ #ifndef X86_WINDOW_H #define X86_WINDOW_H #include "common.h" extern void apply_a52_window_sse(FLOAT *samples); #endif /* X86_WINDOW_H */ aften/libaften/x86/window_sse.c000066400000000000000000000022361132016273200167110ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * * SSE window functions * Copyright (C) 2007 by Prakash Punnoor * prakash@punnoor.de * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; * version 2 of the License * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "libaften/window.h" #include "x86/window.h" #include void apply_a52_window_sse(FLOAT *samples) { int i; for (i=0; i < 512; i += 4) { __m128 input = _mm_load_ps(samples+i); __m128 window = _mm_load_ps(a52_window+i); input = _mm_mul_ps(input, window); _mm_store_ps(samples+i, input); } } aften/pcm/000077500000000000000000000000001132016273200127275ustar00rootroot00000000000000aften/pcm/aiff.c000066400000000000000000000157571132016273200140170ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * Copyright (c) 2007 Justin Ruggles * * Conversion of 80-bit float to double is from FFmpeg intfloat_readwrite.c * Copyright (c) 2005 Michael Niedermayer * * Aften is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * Aften is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with Aften; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file aiff.c * AIFF file format */ #include "common.h" #include "pcm.h" /* IEEE 80 bits extended float */ typedef struct ExtFloat { uint8_t exponent[2]; uint8_t mantissa[8]; } ExtFloat; static double ext2dbl(const ExtFloat ext) { uint64_t m = 0; int e, i; for (i = 0; i < 8; i++) m = (m<<8) + ext.mantissa[i]; e = (((int)ext.exponent[0]&0x7f)<<8) | ext.exponent[1]; if (e == 0x7fff && m) return 0.0; // really should be NaN, but simplifying for portability e -= 16383 + 63; /* In IEEE 80 bits, the whole (i.e. 1.xxxx) * mantissa bit is written as opposed to the * single and double precision formats */ if (ext.exponent[0]&0x80) m= -m; if (e > 0) m <<= e; else if (e < 0) m >>= -e; return m; } /* chunk id's */ #define FORM_ID 0x464F524D #define AIFF_ID 0x41494646 #define COMM_ID 0x434F4D4D #define SSND_ID 0x53534E44 /** * Reads an 80-bit extended float from the input stream */ static inline ExtFloat readext(PcmFile *pf) { ExtFloat x; if (byteio_read(&x, 10, &pf->io) != 10) { memset(&x, 0, sizeof(x)); return x; } pf->filepos += 10; return x; } /** * Reads a 4-byte big-endian word from the input stream */ static inline uint32_t read4be(PcmFile *pf) { uint32_t x; if (byteio_read(&x, 4, &pf->io) != 4) return 0; pf->filepos += 4; return be2me_32(x); } /** * Reads a 2-byte big-endian word from the input stream */ static inline uint16_t read2be(PcmFile *pf) { uint16_t x; if (byteio_read(&x, 2, &pf->io) != 2) return 0; pf->filepos += 2; return be2me_16(x); } static int aiff_probe(uint8_t *data, int size) { int id; if (!data || size < 12) return 0; id = data[3] | (data[2] << 8) | (data[1] << 16) | (data[0] << 24); if (id != FORM_ID) return 0; id = data[11] | (data[10] << 8) | (data[9] << 16) | (data[8] << 24); if (id != AIFF_ID) return 0; return 100; } static int aiff_init(PcmFile *pf) { int id, found_ssnd, found_comm, chunksize, offset; ExtFloat srate_ext; int channels=2, sample_rate=44100, block_align=4, bits=16; enum PcmSampleFormat fmt = PCM_SAMPLE_FMT_S16; // read FORM id. ignore size. id = read4be(pf); if (id != FORM_ID) { fprintf(stderr, "invalid FORM id in aiff header\n"); return -1; } read4be(pf); // read AIFF id. ignore size. id = read4be(pf); if (id != AIFF_ID) { fprintf(stderr, "invalid AIFF id in aiff header\n"); return -1; } // read all header chunks. skip unknown chunks. found_ssnd = found_comm = 0; while (!found_ssnd) { id = read4be(pf); chunksize = read4be(pf); switch (id) { case COMM_ID: if (chunksize < 18) { fprintf(stderr, "invalid COMM chunk in aiff header\n"); return -1; } channels = read2be(pf); pf->samples = read4be(pf); bits = read2be(pf); srate_ext = readext(pf); sample_rate = ext2dbl(srate_ext); block_align = MAX(1, ((bits + 7) >> 3) * channels); pf->ch_mask = pcm_get_default_ch_mask(channels); chunksize -= 18; if (channels == 0) { fprintf(stderr, "invalid number of channels in aiff header\n"); return -1; } if (sample_rate <= 0) { fprintf(stderr, "invalid sample rate in aiff header\n"); return -1; } if (bits == 0) { fprintf(stderr, "invalid sample bit width in aiff header\n"); return -1; } // skip any leftover bytes in fmt chunk chunksize += chunksize & 1; if (pcmfile_seek_set(pf, pf->filepos + chunksize)) { fprintf(stderr, "error seeking in aiff file\n"); return -1; } found_comm = 1; break; case SSND_ID: if (!found_comm) { fprintf(stderr, "COMM after SSND in aiff is not supported\n"); return -1; } offset = read4be(pf); read4be(pf); if (pcmfile_seek_set(pf, pf->filepos + offset)) { fprintf(stderr, "error seeking in aiff file\n"); return -1; } pf->data_size = block_align * pf->samples; pf->data_start = pf->filepos; if (pf->seekable && pf->file_size > 0) { // limit data size to end-of-file pf->data_size = MIN(pf->data_size, pf->file_size - pf->data_start); pf->samples = pf->data_size / block_align; } found_ssnd = 1; break; default: // skip unknown chunk chunksize += chunksize & 1; if (chunksize > 0 && pcmfile_seek_set(pf, pf->filepos + chunksize)) { fprintf(stderr, "error seeking in aiff file\n"); return -1; } } } // set audio data format based on bit depth and sample type fmt = PCM_SAMPLE_FMT_UNKNOWN; switch (bits) { case 8: fmt = PCM_SAMPLE_FMT_S8; break; case 16: fmt = PCM_SAMPLE_FMT_S16; break; case 20: fmt = PCM_SAMPLE_FMT_S20; break; case 24: fmt = PCM_SAMPLE_FMT_S24; break; case 32: fmt = PCM_SAMPLE_FMT_S32; break; default: fprintf(stderr, "unsupported bit depth: %d\n", bits); return -1; } pf->internal_fmt = 0; pcmfile_set_source_params(pf, channels, fmt, PCM_BYTE_ORDER_BE, sample_rate); return 0; } PcmFormat aiff_format = { "aiff", "Apple AIFF", PCM_FORMAT_AIFF, aiff_probe, aiff_init, NULL }; aften/pcm/byteio.c000066400000000000000000000045461132016273200143770ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * Copyright (c) 2007 Justin Ruggles * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file byteio.c * Byte buffer */ #include "byteio.h" int byteio_init(ByteIOContext *ctx, FILE *fp) { ctx->buffer = calloc(BYTEIO_BUFFER_SIZE, 1); if (!ctx->buffer) return -1; ctx->fp = fp; ctx->index = 0; ctx->size = 0; byteio_flush(ctx); return 0; } void byteio_align(ByteIOContext *ctx) { memmove(ctx->buffer, &ctx->buffer[ctx->index], ctx->size); ctx->size += fread(&ctx->buffer[ctx->size], 1, BYTEIO_BUFFER_SIZE-ctx->size, ctx->fp); ctx->index = 0; } int byteio_flush(ByteIOContext *ctx) { ctx->index = 0; ctx->size = fread(ctx->buffer, 1, BYTEIO_BUFFER_SIZE, ctx->fp); return ctx->size; } int byteio_read(void *ptr, int n, ByteIOContext *ctx) { uint8_t *ptr8 = ptr; int count = 0; while (n > ctx->size) { memcpy(&ptr8[count], &ctx->buffer[ctx->index], ctx->size); count += ctx->size; n -= ctx->size; if (byteio_flush(ctx) == 0) break; } if (ctx->size >= n && n > 0) { memcpy(&ptr8[count], &ctx->buffer[ctx->index], n); count += n; ctx->size -= n; ctx->index += n; } return count; } int byteio_peek(void *ptr, int n, ByteIOContext *ctx) { int nr; if (n > ctx->size) byteio_align(ctx); nr = MIN(n, ctx->size); memcpy(ptr, &ctx->buffer[ctx->index], nr); return nr; } void byteio_close(ByteIOContext *ctx) { if (ctx) { ctx->fp = NULL; if (ctx->buffer) free(ctx->buffer); ctx->index = 0; ctx->size = 0; } } aften/pcm/byteio.h000066400000000000000000000026021132016273200143730ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * Copyright (c) 2007 Justin Ruggles * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file byteio.h * Byte buffer header */ #ifndef BYTEIO_H #define BYTEIO_H #include "common.h" #define BYTEIO_BUFFER_SIZE 16384 typedef struct ByteIOContext { FILE *fp; uint8_t *buffer; int index; int size; } ByteIOContext; extern int byteio_init(ByteIOContext *ctx, FILE *fp); extern void byteio_align(ByteIOContext *ctx); extern int byteio_flush(ByteIOContext *ctx); extern int byteio_read(void *ptr, int n, ByteIOContext *ctx); extern int byteio_peek(void *ptr, int n, ByteIOContext *ctx); extern void byteio_close(ByteIOContext *ctx); #endif /* BYTEIO_H */ aften/pcm/caff.c000066400000000000000000000142001132016273200137670ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * Copyright (c) 2007 Justin Ruggles * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file caff.c * Apple Core Audio File Format (CAFF) */ #include "pcm.h" #define CAFF_ID 0x63616666 #define DESC_ID 0x64657363 #define DATA_ID 0x64617461 #define LPCM_TAG 0x6C70636D #define FLAG_IS_FLOAT 0x1 #define FLAG_IS_LITTLEENDIAN 0x2 /** * Reads a 8-byte big-endian word from the input stream */ static inline uint64_t read8be(PcmFile *pf) { uint64_t x; if (byteio_read(&x, 8, &pf->io) != 8) return 0; pf->filepos += 8; return be2me_64(x); } /** * Reads a 8-byte big-endian word from the input stream as a double value */ static inline double read_dbl_be(PcmFile *pf) { union { uint64_t i; double d; } x; x.i = read8be(pf); return x.d; } /** * Reads a 4-byte big-endian word from the input stream */ static inline uint32_t read4be(PcmFile *pf) { uint32_t x; if (byteio_read(&x, 4, &pf->io) != 4) return 0; pf->filepos += 4; return be2me_32(x); } /** * Reads a 2-byte big-endian word from the input stream */ static inline uint16_t read2be(PcmFile *pf) { uint16_t x; if (byteio_read(&x, 2, &pf->io) != 2) return 0; pf->filepos += 2; return be2me_16(x); } static int caff_probe(uint8_t *data, int size) { int id; if (!data || size < 6) return 0; id = data[3] | (data[2] << 8) | (data[1] << 16) | (data[0] << 24); if (id == CAFF_ID && data[4] == 0 && data[5] == 1) return 100; return 0; } static int caff_init(PcmFile *pf) { int id, found_data, format_flags; enum PcmSampleFormat src_fmt; uint64_t chunksize; // read "caff" id if (read4be(pf) != CAFF_ID) { fprintf(stderr, "CAFF: file type check failed\n"); return -1; } // check file version if (read2be(pf) != 1) { fprintf(stderr, "CAFF: file version check failed\n"); return -1; } // skip file flags read2be(pf); // audio description chunk if (read4be(pf) != DESC_ID) { fprintf(stderr, "CAFF: 'desc' chunk not present\n"); return -1; } chunksize = read8be(pf); if (chunksize != 32) { fprintf(stderr, "CAFF: invalid 'desc' chunk size\n"); return -1; } pf->sample_rate = read_dbl_be(pf); pf->internal_fmt = read4be(pf); format_flags = read4be(pf); pf->order = (format_flags & FLAG_IS_LITTLEENDIAN) ? PCM_BYTE_ORDER_LE: PCM_BYTE_ORDER_BE; pf->sample_type = (format_flags & FLAG_IS_FLOAT) ? PCM_SAMPLE_TYPE_FLOAT: PCM_SAMPLE_TYPE_INT; pf->block_align = read4be(pf); read4be(pf); pf->channels = read4be(pf); pf->ch_mask = pcm_get_default_ch_mask(pf->channels); pf->bit_width = read4be(pf); // validate some parameters if (pf->sample_rate < 1) { fprintf(stderr, "CAFF: Invalid sample rate: %d\n", pf->sample_rate); return -1; } if (pf->block_align < 1) { fprintf(stderr, "CAFF: Invalid block align: %d\n", pf->block_align); return -1; } if (pf->channels < 1 || pf->channels > PCM_MAX_CHANNELS) { fprintf(stderr, "CAFF: Invalid number of channels: %d\n", pf->channels); return -1; } if (pf->internal_fmt != LPCM_TAG) { fprintf(stderr, "CAFF: Unsupported codec: 0x%04X\n", pf->internal_fmt); return -1; } // set audio data format based on bit depth and sample type src_fmt = PCM_SAMPLE_FMT_UNKNOWN; switch (pf->bit_width) { case 8: src_fmt = PCM_SAMPLE_FMT_S8; break; case 16: src_fmt = PCM_SAMPLE_FMT_S16; break; case 20: src_fmt = PCM_SAMPLE_FMT_S20; break; case 24: src_fmt = PCM_SAMPLE_FMT_S24; break; case 32: if (pf->sample_type == PCM_SAMPLE_TYPE_FLOAT) src_fmt = PCM_SAMPLE_FMT_FLT; else if (pf->sample_type == PCM_SAMPLE_TYPE_INT) src_fmt = PCM_SAMPLE_FMT_S32; break; case 64: if (pf->sample_type == PCM_SAMPLE_TYPE_FLOAT) { src_fmt = PCM_SAMPLE_FMT_DBL; } else { fprintf(stderr, "64-bit integer samples not supported\n"); return -1; } break; } pcmfile_set_source_format(pf, src_fmt); // read all header chunks. skip unknown chunks. found_data = 0; while (!found_data) { id = read4be(pf); chunksize = read8be(pf); switch (id) { case DATA_ID: read4be(pf); pf->data_size = chunksize - 4; pf->data_start = pf->filepos; if (pf->seekable && pf->file_size > 0) { // limit data size to end-of-file if (pf->data_size > 0) pf->data_size = MIN(pf->data_size, pf->file_size - pf->data_start); else pf->data_size = pf->file_size - pf->data_start; } pf->samples = (pf->data_size / pf->block_align); found_data = 1; break; default: // skip unknown chunk if (chunksize > 0 && pcmfile_seek_set(pf, pf->filepos + chunksize)) { fprintf(stderr, "error seeking in CAFF file\n"); return -1; } } } return 0; } PcmFormat caff_format = { "caff", "Apple CAFF", PCM_FORMAT_CAFF, caff_probe, caff_init, NULL }; aften/pcm/convert.c000066400000000000000000000376631132016273200145720ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * Copyright (c) 2006 Justin Ruggles * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file convert.c * Raw audio sample format conversion */ #include "pcm.h" static void fmt_convert_u8_to_u8(void *dest_v, void *src_v, int n) { memcpy(dest_v, src_v, n * sizeof(uint8_t)); } static void fmt_convert_s8_to_u8(void *dest_v, void *src_v, int n) { uint8_t *dest = dest_v; int8_t *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = (int)src[i] + 128; } static void fmt_convert_s16_to_u8(void *dest_v, void *src_v, int n) { uint8_t *dest = dest_v; int16_t *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = (src[i] >> 8) + 128; } static void fmt_convert_s20_to_u8(void *dest_v, void *src_v, int n) { uint8_t *dest = dest_v; int32_t *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = (src[i] >> 12) + 128; } static void fmt_convert_s24_to_u8(void *dest_v, void *src_v, int n) { uint8_t *dest = dest_v; int32_t *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = (src[i] >> 16) + 128; } static void fmt_convert_s32_to_u8(void *dest_v, void *src_v, int n) { uint8_t *dest = dest_v; int32_t *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = (src[i] >> 24) + 128; } static void fmt_convert_float_to_u8(void *dest_v, void *src_v, int n) { uint8_t *dest = dest_v; float *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = (uint8_t)CLIP(((src[i] * 128) + 128), 0, 255); } static void fmt_convert_double_to_u8(void *dest_v, void *src_v, int n) { uint8_t *dest = dest_v; double *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = (uint8_t)CLIP(((src[i] * 128) + 128), 0, 255); } static void fmt_convert_u8_to_s8(void *dest_v, void *src_v, int n) { int8_t *dest = dest_v; uint8_t *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = (int)src[i] - 128; } static void fmt_convert_s8_to_s8(void *dest_v, void *src_v, int n) { memcpy(dest_v, src_v, n * sizeof(int8_t)); } static void fmt_convert_s16_to_s8(void *dest_v, void *src_v, int n) { int8_t *dest = dest_v; int16_t *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = src[i] >> 8; } static void fmt_convert_s20_to_s8(void *dest_v, void *src_v, int n) { int8_t *dest = dest_v; int32_t *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = src[i] >> 12; } static void fmt_convert_s24_to_s8(void *dest_v, void *src_v, int n) { int8_t *dest = dest_v; int32_t *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = src[i] >> 16; } static void fmt_convert_s32_to_s8(void *dest_v, void *src_v, int n) { int8_t *dest = dest_v; int32_t *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = src[i] >> 24; } static void fmt_convert_float_to_s8(void *dest_v, void *src_v, int n) { int8_t *dest = dest_v; float *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = (int8_t)CLIP((src[i] * 128), -128, 127); } static void fmt_convert_double_to_s8(void *dest_v, void *src_v, int n) { int8_t *dest = dest_v; double *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = (int8_t)CLIP((src[i] * 128), -128, 127); } static void fmt_convert_u8_to_s16(void *dest_v, void *src_v, int n) { int16_t *dest = dest_v; uint8_t *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = (src[i] - 128) << 8; } static void fmt_convert_s8_to_s16(void *dest_v, void *src_v, int n) { int16_t *dest = dest_v; int8_t *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = src[i] << 8; } static void fmt_convert_s16_to_s16(void *dest_v, void *src_v, int n) { memcpy(dest_v, src_v, n * sizeof(int16_t)); } static void fmt_convert_s20_to_s16(void *dest_v, void *src_v, int n) { int16_t *dest = dest_v; int32_t *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = (src[i] >> 4); } static void fmt_convert_s24_to_s16(void *dest_v, void *src_v, int n) { int16_t *dest = dest_v; int32_t *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = (src[i] >> 8); } static void fmt_convert_s32_to_s16(void *dest_v, void *src_v, int n) { int16_t *dest = dest_v; int32_t *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = (src[i] >> 16); } static void fmt_convert_float_to_s16(void *dest_v, void *src_v, int n) { int16_t *dest = dest_v; float *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = (int16_t)CLIP((src[i] * 32768), -32768, 32767); } static void fmt_convert_double_to_s16(void *dest_v, void *src_v, int n) { int16_t *dest = dest_v; double *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = (int16_t)CLIP((src[i] * 32768), -32768, 32767); } static void fmt_convert_u8_to_s20(void *dest_v, void *src_v, int n) { int32_t *dest = dest_v; uint8_t *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = (src[i] - 128) << 12; } static void fmt_convert_s8_to_s20(void *dest_v, void *src_v, int n) { int32_t *dest = dest_v; int8_t *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = src[i] << 12; } static void fmt_convert_s16_to_s20(void *dest_v, void *src_v, int n) { int32_t *dest = dest_v; int16_t *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = (src[i] << 4); } static void fmt_convert_s20_to_s20(void *dest_v, void *src_v, int n) { memcpy(dest_v, src_v, n * sizeof(int32_t)); } static void fmt_convert_s24_to_s20(void *dest_v, void *src_v, int n) { int32_t *dest = dest_v; int32_t *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = (src[i] >> 4); } static void fmt_convert_s32_to_s20(void *dest_v, void *src_v, int n) { int32_t *dest = dest_v; int32_t *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = (src[i] >> 12); } static void fmt_convert_float_to_s20(void *dest_v, void *src_v, int n) { int32_t *dest = dest_v; float *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = (int32_t)CLIP((src[i] * 524288), -524288, 524287); } static void fmt_convert_double_to_s20(void *dest_v, void *src_v, int n) { int32_t *dest = dest_v; double *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = (int32_t)CLIP((src[i] * 524288), -524288, 524287); } static void fmt_convert_u8_to_s24(void *dest_v, void *src_v, int n) { int32_t *dest = dest_v; uint8_t *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = (src[i] - 128) << 16; } static void fmt_convert_s8_to_s24(void *dest_v, void *src_v, int n) { int32_t *dest = dest_v; int8_t *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = src[i] << 16; } static void fmt_convert_s16_to_s24(void *dest_v, void *src_v, int n) { int32_t *dest = dest_v; int16_t *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = (src[i] << 8); } static void fmt_convert_s20_to_s24(void *dest_v, void *src_v, int n) { int32_t *dest = dest_v; int32_t *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = (src[i] << 4); } static void fmt_convert_s24_to_s24(void *dest_v, void *src_v, int n) { memcpy(dest_v, src_v, n * sizeof(int32_t)); } static void fmt_convert_s32_to_s24(void *dest_v, void *src_v, int n) { int32_t *dest = dest_v; int32_t *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = (src[i] >> 8); } static void fmt_convert_float_to_s24(void *dest_v, void *src_v, int n) { int32_t *dest = dest_v; float *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = (int32_t)CLIP((src[i] * 8388608), -8388608, 8388607); } static void fmt_convert_double_to_s24(void *dest_v, void *src_v, int n) { int32_t *dest = dest_v; double *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = (int32_t)CLIP((src[i] * 8388608), -8388608, 8388607); } static void fmt_convert_u8_to_s32(void *dest_v, void *src_v, int n) { int32_t *dest = dest_v; uint8_t *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = (src[i] - 128) << 24; } static void fmt_convert_s8_to_s32(void *dest_v, void *src_v, int n) { int32_t *dest = dest_v; int8_t *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = src[i] << 24; } static void fmt_convert_s16_to_s32(void *dest_v, void *src_v, int n) { int32_t *dest = dest_v; int16_t *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = (src[i] << 16); } static void fmt_convert_s20_to_s32(void *dest_v, void *src_v, int n) { int32_t *dest = dest_v; int32_t *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = (src[i] << 12); } static void fmt_convert_s24_to_s32(void *dest_v, void *src_v, int n) { int32_t *dest = dest_v; int32_t *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = (src[i] << 8); } static void fmt_convert_s32_to_s32(void *dest_v, void *src_v, int n) { memcpy(dest_v, src_v, n * sizeof(int32_t)); } static void fmt_convert_float_to_s32(void *dest_v, void *src_v, int n) { int32_t *dest = dest_v; float *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = (int32_t)(src[i] * 2147483648LL); } static void fmt_convert_double_to_s32(void *dest_v, void *src_v, int n) { int32_t *dest = dest_v; double *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = (int32_t)(src[i] * 2147483648LL); } static void fmt_convert_u8_to_float(void *dest_v, void *src_v, int n) { float *dest = dest_v; uint8_t *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = (src[i] - 128.0) / 128.0; } static void fmt_convert_s8_to_float(void *dest_v, void *src_v, int n) { float *dest = dest_v; int8_t *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = src[i] / 128.0; } static void fmt_convert_s16_to_float(void *dest_v, void *src_v, int n) { float *dest = dest_v; int16_t *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = src[i] / 32768.0; } static void fmt_convert_s20_to_float(void *dest_v, void *src_v, int n) { float *dest = dest_v; int32_t *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = src[i] / 524288.0; } static void fmt_convert_s24_to_float(void *dest_v, void *src_v, int n) { float *dest = dest_v; int32_t *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = src[i] / 8388608.0; } static void fmt_convert_s32_to_float(void *dest_v, void *src_v, int n) { float *dest = dest_v; int32_t *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = src[i] / 2147483648.0; } static void fmt_convert_float_to_float(void *dest_v, void *src_v, int n) { memcpy(dest_v, src_v, n * sizeof(float)); } static void fmt_convert_double_to_float(void *dest_v, void *src_v, int n) { float *dest = dest_v; double *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = (float)src[i]; } static void fmt_convert_u8_to_double(void *dest_v, void *src_v, int n) { double *dest = dest_v; uint8_t *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = (src[i] - 128.0) / 128.0; } static void fmt_convert_s8_to_double(void *dest_v, void *src_v, int n) { double *dest = dest_v; int8_t *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = src[i] / 128.0; } static void fmt_convert_s16_to_double(void *dest_v, void *src_v, int n) { double *dest = dest_v; int16_t *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = src[i] / 32768.0; } static void fmt_convert_s20_to_double(void *dest_v, void *src_v, int n) { double *dest = dest_v; int32_t *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = src[i] / 524288.0; } static void fmt_convert_s24_to_double(void *dest_v, void *src_v, int n) { double *dest = dest_v; int32_t *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = src[i] / 8388608.0; } static void fmt_convert_s32_to_double(void *dest_v, void *src_v, int n) { double *dest = dest_v; int32_t *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = src[i] / 2147483648.0; } static void fmt_convert_float_to_double(void *dest_v, void *src_v, int n) { double *dest = dest_v; float *src = src_v; int i; for (i = 0; i < n; i++) dest[i] = src[i]; } static void fmt_convert_double_to_double(void *dest_v, void *src_v, int n) { memcpy(dest_v, src_v, n * sizeof(double)); } #define SET_FMT_CONVERT_FROM(srcfmt, pf) \ { \ enum PcmSampleFormat rfmt = pf->read_format; \ \ if (rfmt == PCM_SAMPLE_FMT_U8) \ pf->fmt_convert = fmt_convert_##srcfmt##_to_u8; \ else if (rfmt == PCM_SAMPLE_FMT_S8) \ pf->fmt_convert = fmt_convert_##srcfmt##_to_s8; \ else if (rfmt == PCM_SAMPLE_FMT_S16) \ pf->fmt_convert = fmt_convert_##srcfmt##_to_s16; \ else if (rfmt == PCM_SAMPLE_FMT_S20) \ pf->fmt_convert = fmt_convert_##srcfmt##_to_s20; \ else if (rfmt == PCM_SAMPLE_FMT_S24) \ pf->fmt_convert = fmt_convert_##srcfmt##_to_s24; \ else if (rfmt == PCM_SAMPLE_FMT_S32) \ pf->fmt_convert = fmt_convert_##srcfmt##_to_s32; \ else if (rfmt == PCM_SAMPLE_FMT_FLT) \ pf->fmt_convert = fmt_convert_##srcfmt##_to_float; \ else if (rfmt == PCM_SAMPLE_FMT_DBL) \ pf->fmt_convert = fmt_convert_##srcfmt##_to_double; \ } void pcmfile_set_source_format(PcmFile *pf, enum PcmSampleFormat fmt) { static const int fmt_bits[8] = { 8, 8, 16, 20, 24, 32, 32, 64 }; fmt = CLIP(fmt, PCM_SAMPLE_FMT_U8, PCM_SAMPLE_FMT_DBL); pf->source_format = fmt; pf->bit_width = fmt_bits[fmt]; switch (fmt) { case PCM_SAMPLE_FMT_U8: SET_FMT_CONVERT_FROM(u8, pf); break; case PCM_SAMPLE_FMT_S8: SET_FMT_CONVERT_FROM(s8, pf); break; case PCM_SAMPLE_FMT_S16: SET_FMT_CONVERT_FROM(s16, pf); break; case PCM_SAMPLE_FMT_S20: SET_FMT_CONVERT_FROM(s20, pf); break; case PCM_SAMPLE_FMT_S24: SET_FMT_CONVERT_FROM(s24, pf); break; case PCM_SAMPLE_FMT_S32: SET_FMT_CONVERT_FROM(s32, pf); break; case PCM_SAMPLE_FMT_FLT: SET_FMT_CONVERT_FROM(float, pf); break; case PCM_SAMPLE_FMT_DBL: SET_FMT_CONVERT_FROM(double, pf); break; default: break; } if (fmt == PCM_SAMPLE_FMT_FLT || fmt == PCM_SAMPLE_FMT_DBL) pf->sample_type = PCM_SAMPLE_TYPE_FLOAT; else pf->sample_type = PCM_SAMPLE_TYPE_INT; pf->block_align = MAX(1, ((pf->bit_width + 7) >> 3) * pf->channels); pf->samples = (pf->data_size / pf->block_align); } void pcmfile_set_source_params(PcmFile *pf, int ch, enum PcmSampleFormat fmt, int order, int sr) { pf->channels = MAX(ch, 1); pf->ch_mask = pcm_get_default_ch_mask(ch); pf->order = CLIP(order, PCM_BYTE_ORDER_LE, PCM_BYTE_ORDER_BE); pf->sample_rate = MAX(sr, 1); pcmfile_set_source_format(pf, fmt); } void pcmfile_set_read_format(PcmFile *pf, enum PcmSampleFormat read_format) { pf->read_format = CLIP(read_format, PCM_SAMPLE_FMT_U8, PCM_SAMPLE_FMT_DBL); pcmfile_set_source_format(pf, pf->source_format); } aften/pcm/formats.c000066400000000000000000000042421132016273200145500ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * Copyright (c) 2007 Justin Ruggles * * Basic concept and code structure for formats is based on FFmpeg libavformat * Copyright (c) 2000-2007 Fabrice Bellard, et al. * * Aften is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * Aften is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with Aften; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file formats.c * file format registration and detection */ #include "formats.h" #define REGISTER_FORMAT(x) { \ extern PcmFormat x##_format; \ pcmfile_register_format(&x##_format); } void pcmfile_register_all_formats(void) { static int inited; if (inited) return; inited = 1; REGISTER_FORMAT(raw); REGISTER_FORMAT(wave); REGISTER_FORMAT(aiff); REGISTER_FORMAT(caff); } PcmFormat *first_format = NULL; void pcmfile_register_format(PcmFormat *format) { PcmFormat **p; p = &first_format; while (*p != NULL) p = &(*p)->next; *p = format; format->next = NULL; } PcmFormat * pcmfile_find_format(int format) { PcmFormat *fmt; for (fmt = first_format; fmt != NULL; fmt = fmt->next) { if (fmt->format == format) return fmt; } return NULL; } PcmFormat * pcmfile_probe_format(uint8_t *data, int size) { PcmFormat *fmt1, *fmt; int score, score_max; score_max = 0; fmt = NULL; for (fmt1 = first_format; fmt1 != NULL; fmt1 = fmt1->next) { score = 0; if (fmt1->probe) score = fmt1->probe(data, size); if (score > score_max) { score_max = score; fmt = fmt1; } } return fmt; } aften/pcm/formats.h000066400000000000000000000033121132016273200145520ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * Copyright (c) 2007 Justin Ruggles * * Basic concept and code structure for formats is based on FFmpeg libavformat * Copyright (c) 2000-2007 Fabrice Bellard, et al. * * Aften is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * Aften is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with Aften; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file formats.c * file format registration and detection header */ #ifndef FORMATS_H #define FORMATS_H #include "common.h" /* supported file formats */ enum PcmFileFormat { PCM_FORMAT_UNKNOWN = -1, PCM_FORMAT_RAW = 0, PCM_FORMAT_WAVE = 1, PCM_FORMAT_AIFF = 2, PCM_FORMAT_CAFF = 3 }; struct PcmFile; typedef struct PcmFormat { const char *name; const char *long_name; int format; int (*probe)(uint8_t *data, int size); int (*init)(struct PcmFile *pf); struct PcmFormat *next; } PcmFormat; extern void pcmfile_register_all_formats(void); extern void pcmfile_register_format(PcmFormat *format); extern PcmFormat *pcmfile_find_format(int format); extern PcmFormat *pcmfile_probe_format(uint8_t *data, int size); #endif /* FORMATS_H */ aften/pcm/pcm.c000066400000000000000000000140431132016273200136540ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * Copyright (c) 2007 Justin Ruggles * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file pcm.c * raw PCM multi-file decoder */ #include "pcm.h" int pcm_init(PcmContext *pc, int num_files, FILE **fp_list, enum PcmSampleFormat read_format, int file_format) { int i; uint64_t samples; // check parameters if (num_files < 1 || num_files > PCM_MAX_CHANNELS) { fprintf(stderr, "invalid number of files: %d. must be > 0\n", num_files); return -1; } if (read_format < PCM_SAMPLE_FMT_U8 || read_format > PCM_SAMPLE_FMT_DBL) { fprintf(stderr, "invalid read format: %d\n", read_format); return -1; } if (file_format < PCM_FORMAT_UNKNOWN || file_format > PCM_FORMAT_CAFF) { fprintf(stderr, "invalid file format: %d\n", file_format); return -1; } memset(pc, 0, sizeof(PcmContext)); samples = 0; for (i = 0; i < num_files; i++) { PcmFile *pf = &pc->pcm_file[i]; if (pcmfile_init(pf, fp_list[i], read_format, file_format)) { fprintf(stderr, "error initializing file #%d\n", i); pcm_close(pc); return -1; } if (num_files > 1 && pf->channels != 1) { fprintf(stderr, "all files must be mono when using multiple input files\n"); pcm_close(pc); return -1; } samples = MAX(samples, pc->pcm_file[i].samples); } pc->samples = samples; pc->num_files = num_files; pc->read_format = read_format; if (num_files == 1) { pc->channels = pc->pcm_file[0].channels; pc->ch_mask = pc->pcm_file[0].ch_mask; } else { pc->channels = num_files; pc->ch_mask = pcm_get_default_ch_mask(pc->channels); } pcm_set_sample_rate(pc, pc->pcm_file[0].sample_rate); return 0; } void pcm_close(PcmContext *pc) { int i; for (i = 0; i < pc->num_files; i++) pcmfile_close(&pc->pcm_file[i]); memset(pc, 0, sizeof(PcmContext)); } void pcm_set_source_format(PcmContext *pc, enum PcmSampleFormat fmt) { int i; for (i = 0; i < pc->num_files; i++) pcmfile_set_source_format(&pc->pcm_file[i], fmt); } void pcm_set_source_params(PcmContext *pc, int ch, enum PcmSampleFormat fmt, int order, int sr) { int i; if (pc->num_files > 1 && ch != 1) { fprintf(stderr, "all files must be mono when using multiple input files\n"); return; } for (i = 0; i < pc->num_files; i++) pcmfile_set_source_params(&pc->pcm_file[i], ch, fmt, order, sr); pc->sample_rate = sr; if (pc->num_files == 1) { pc->channels = pc->pcm_file[0].channels; pc->ch_mask = pcm_get_default_ch_mask(pc->channels); } } void pcm_set_sample_rate(PcmContext *pc, int sample_rate) { int i; pc->sample_rate = sample_rate; for (i = 0; i < pc->num_files; i++) pc->pcm_file[i].sample_rate = sample_rate; } void pcm_set_read_to_eof(PcmContext *pc, int read_to_eof) { int i; pc->read_to_eof = read_to_eof; for (i = 0; i < pc->num_files; i++) pc->pcm_file[i].read_to_eof = read_to_eof; } void pcm_set_read_format(PcmContext *pc, enum PcmSampleFormat read_format) { int i; pc->read_format = read_format; for (i = 0; i < pc->num_files; i++) pcmfile_set_read_format(&pc->pcm_file[i], read_format); } void pcm_print(PcmContext *pc, FILE *st) { int i; for (i = 0; i < pc->num_files; i++) pcmfile_print(&pc->pcm_file[i], st); } static const uint8_t sample_sizes[8] = { 1, 1, 2, 4, 4, 4, 4, 8 }; #define CHANNEL_INTERLEAVE_COMMON(DATA_TYPE) \ { \ DATA_TYPE *input = (DATA_TYPE *)buf; \ DATA_TYPE *output = buffer; \ int j, k; \ \ for (i = 0, k = 0; i < samples_read; i++) \ for (j = 0; j < pc->num_files; j++, k++) \ output[k] = input[num_samples * j + i]; \ } int pcm_read_samples(PcmContext *pc, void *buffer, int num_samples) { int i; int samples_read, chansize; uint8_t *buf; uint8_t *buf_ptr; if (pc->num_files == 1) return pcmfile_read_samples(&pc->pcm_file[0], buffer, num_samples); /* allocate buffer */ chansize = num_samples * sample_sizes[pc->read_format]; buf = calloc(1, chansize * pc->channels); if (!buf) return -1; /* read samples from each channel */ samples_read = 0; buf_ptr = buf; for (i = 0; i < pc->num_files; i++) { int nr = pcmfile_read_samples(&pc->pcm_file[i], buf_ptr, num_samples); if (nr < 0) { free(buf); return -1; } samples_read = MAX(samples_read, nr); buf_ptr += chansize; } /* interleave samples to create multichannel */ switch (pc->read_format) { case PCM_SAMPLE_FMT_U8: CHANNEL_INTERLEAVE_COMMON(uint8_t) break; case PCM_SAMPLE_FMT_S8: CHANNEL_INTERLEAVE_COMMON(int8_t) break; case PCM_SAMPLE_FMT_S16: CHANNEL_INTERLEAVE_COMMON(int16_t) break; case PCM_SAMPLE_FMT_S20: case PCM_SAMPLE_FMT_S24: case PCM_SAMPLE_FMT_S32: CHANNEL_INTERLEAVE_COMMON(int32_t) break; case PCM_SAMPLE_FMT_FLT: CHANNEL_INTERLEAVE_COMMON(float) break; case PCM_SAMPLE_FMT_DBL: CHANNEL_INTERLEAVE_COMMON(double) break; } free(buf); return samples_read; } aften/pcm/pcm.h000066400000000000000000000065731132016273200136720ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * Copyright (c) 2007 Justin Ruggles * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file pcm.h * raw PCM decoder header */ #ifndef PCM_H #define PCM_H #include "pcmfile.h" typedef struct PcmContext { PcmFile pcm_file[PCM_MAX_CHANNELS]; ///< source files int num_files; ///< number of source files uint64_t samples; ///< maximum number of samples for all files int channels; ///< number of channels int ch_mask; ///< channel mask. tells which channels are present int sample_rate; ///< sample rate for all files int read_to_eof; ///< indicates that data is to be read until EOF int read_format; ///< sample type to convert to when reading } PcmContext; /** * Initializes PcmContext structure using the given input file pointers. * Examines the header (if present) to get audio information and has the file * pointer aligned at start of data when it exits. * * @param pc The PcmContext to initialize * @param num_files Number of source files * @param fp_list Array of file pointers to source files * @param read_format Sample format to convert to when reading * @param file_format Source file format, or PCM_FORMAT_UNKNOWN to autodetect * * @return non-zero value if an error occurs. */ extern int pcm_init(PcmContext *pc, int num_files, FILE **fp_list, enum PcmSampleFormat read_format, int file_format); /** * Frees memory from internal buffer. */ extern void pcm_close(PcmContext *pc); /** * Sets the source sample format for all files */ extern void pcm_set_source_format(PcmContext *pc, enum PcmSampleFormat fmt); /** * Sets source audio information for all files */ extern void pcm_set_source_params(PcmContext *pc, int ch, enum PcmSampleFormat fmt, int order, int sr); /** * Sets source audio information for all files */ extern void pcm_set_sample_rate(PcmContext *pc, int sample_rate); /** * Sets the read_to_eof parameter for all files */ extern void pcm_set_read_to_eof(PcmContext *pc, int read_to_eof); /** * Sets the requested read format */ extern void pcm_set_read_format(PcmContext *pc, enum PcmSampleFormat read_format); /** * Prints out a description of the pcm format to the specified * output stream. */ extern void pcm_print(PcmContext *pc, FILE *st); /** * Reads audio samples to the output buffer. * Output is channel-interleaved, native byte order. * Only up to PCM_MAX_READ samples can be read in one call. * The output sample format depends on the value of pc->read_format. * Returns number of samples read or -1 on error. */ extern int pcm_read_samples(PcmContext *pc, void *buffer, int num_samples); #endif /* PCM_H */ aften/pcm/pcm_io.c000066400000000000000000000171011132016273200143410ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * Copyright (c) 2006 Justin Ruggles * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file pcm_io.c * raw PCM file i/o */ #include "pcmfile.h" #ifdef WORDS_BIGENDIAN #define PCM_NON_NATIVE_BYTE_ORDER PCM_BYTE_ORDER_LE #else #define PCM_NON_NATIVE_BYTE_ORDER PCM_BYTE_ORDER_BE #endif int pcmfile_seek_set(PcmFile *pf, uint64_t dest) { FILE *fp = pf->io.fp; int slow_seek = !(pf->seekable); if (pf->seekable) { if (dest <= INT32_MAX) { // destination is within first 2GB if (fseek(fp, (long)dest, SEEK_SET)) return -1; } else { int64_t offset = (int64_t)dest - (int64_t)pf->filepos; if (offset >= INT32_MIN && offset <= INT32_MAX) { // offset is within +/- 2GB of file start if (fseek(fp, (long)offset, SEEK_CUR)) return -1; } else { // absolute offset is more than 2GB if (offset < 0) { fprintf(stderr, "error: backward seeking is limited to 2GB\n"); return -1; } else { fprintf(stderr, "warning: forward seeking more than 2GB will be slow.\n"); } slow_seek = 1; } } byteio_flush(&pf->io); } if (slow_seek) { // do forward-only seek by reading data to temp buffer uint64_t offset; uint8_t buf[1024]; if (dest < pf->filepos) return -1; for (offset = dest - pf->filepos; offset > 1024; offset -= 1024) byteio_read(buf, 1024, &pf->io); byteio_read(buf, (int)offset, &pf->io); } pf->filepos = dest; return 0; } int pcmfile_read_samples(PcmFile *pf, void *output, int num_samples) { uint8_t *buffer; uint8_t *read_buffer; uint32_t bytes_needed, buffer_size; int nr, i, j, bps, nsmp; // check input and limit number of samples if (pf == NULL || pf->io.fp == NULL || output == NULL || pf->fmt_convert == NULL) { fprintf(stderr, "null input to pcmfile_read_samples()\n"); return -1; } if (pf->block_align <= 0) { fprintf(stderr, "invalid block_align\n"); return -1; } num_samples = MIN(num_samples, PCM_MAX_READ); // calculate number of bytes to read, being careful not to read past // the end of the data chunk bytes_needed = pf->block_align * num_samples; if (!pf->read_to_eof) { if ((pf->filepos + bytes_needed) >= (pf->data_start + pf->data_size)) { bytes_needed = (uint32_t)((pf->data_start + pf->data_size) - pf->filepos); num_samples = bytes_needed / pf->block_align; } } if (num_samples <= 0) return 0; // allocate temporary buffer for raw input data bps = pf->block_align / pf->channels; buffer_size = (bps != 3) ? bytes_needed : num_samples * sizeof(int32_t) * pf->channels; buffer = calloc(buffer_size + 1, 1); if (!buffer) { fprintf(stderr, "error allocating read buffer\n"); return -1; } read_buffer = buffer + (buffer_size - bytes_needed); // read raw audio samples from input stream into temporary buffer nr = byteio_read(read_buffer, bytes_needed, &pf->io); if (nr <= 0) { free(buffer); return nr; } pf->filepos += nr; nr /= pf->block_align; nsmp = nr * pf->channels; // do any necessary conversion based on source_format and read_format. // also do byte swapping when necessary based on source audio and system // byte orders. switch (bps) { case 2: if (pf->order == PCM_NON_NATIVE_BYTE_ORDER) { uint16_t *buf16 = (uint16_t *)buffer; for (i = 0; i < nsmp; i++) buf16[i] = bswap_16(buf16[i]); } break; case 3: { int32_t *input = (int32_t*)buffer; int unused_bits = 32 - pf->bit_width; int32_t v; if (pf->order == PCM_NON_NATIVE_BYTE_ORDER) { for (i = 0, j = 0; i < nsmp*bps; i += bps, j++) { v = bswap_32(*(uint32_t*)(read_buffer + i) << 8); v <<= unused_bits; // clear unused high bits v >>= unused_bits; // sign extend input[j] = v; } } else { for (i = 0, j = 0; i < nsmp*bps; i += bps, j++) { v = *(int32_t*)(read_buffer + i); v <<= unused_bits; // clear unused high bits v >>= unused_bits; // sign extend input[j] = v; } } } break; case 4: if (pf->order == PCM_NON_NATIVE_BYTE_ORDER) { uint32_t *buf32 = (uint32_t *)buffer; for (i = 0; i < nsmp; i++) buf32[i] = bswap_32(buf32[i]); } break; case 8: if (pf->order == PCM_NON_NATIVE_BYTE_ORDER) { uint64_t *buf64 = (uint64_t *)buffer; for (i = 0; i < nsmp; i++) buf64[i] = bswap_64(buf64[i]); } break; } pf->fmt_convert(output, buffer, nsmp); // free temporary buffer free(buffer); return nr; } int pcmfile_seek_samples(PcmFile *pf, int64_t offset, int whence) { int64_t byte_offset; uint64_t newpos, fpos, dst, dsz; if (pf == NULL || pf->io.fp == NULL) return -1; if (pf->block_align <= 0) return -1; if (pf->filepos < pf->data_start) return -1; if (pf->data_size == 0) return 0; fpos = pf->filepos; dst = pf->data_start; dsz = pf->data_size; byte_offset = offset; byte_offset *= pf->block_align; // calculate new destination within file switch (whence) { case PCM_SEEK_SET: newpos = dst + CLIP(byte_offset, 0, (int64_t)dsz); break; case PCM_SEEK_CUR: newpos = fpos - MIN(-byte_offset, (int64_t)(fpos - dst)); newpos = MIN(newpos, dst + dsz); break; case PCM_SEEK_END: newpos = dst + dsz - CLIP(byte_offset, 0, (int64_t)dsz); break; default: return -1; } // seek to the destination point if (pcmfile_seek_set(pf, newpos)) return -1; return 0; } int pcmfile_seek_time_ms(PcmFile *pf, int64_t offset, int whence) { int64_t samples; if (pf == NULL) return -1; samples = offset * pf->sample_rate / 1000; return pcmfile_seek_samples(pf, samples, whence); } uint64_t pcmfile_position(PcmFile *pf) { uint64_t cur; if (pf == NULL) return -1; if (pf->block_align <= 0) return -1; if (pf->data_start == 0 || pf->data_size == 0) return 0; cur = (pf->filepos - pf->data_start) / pf->block_align; return cur; } uint64_t pcmfile_position_time_ms(PcmFile *pf) { return (pcmfile_position(pf) * 1000 / pf->sample_rate); } aften/pcm/pcmfile.c000066400000000000000000000116701132016273200145170ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * Copyright (c) 2006 Justin Ruggles * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file pcmfile.c * raw PCM decoder */ #include "pcmfile.h" int pcmfile_init(PcmFile *pf, FILE *fp, enum PcmSampleFormat read_format, int file_format) { if (pf == NULL || fp == NULL) { fprintf(stderr, "null input to pcmfile_init()\n"); return -1; } pf->read_to_eof = 0; pf->file_format = file_format; pf->read_format = read_format; // attempt to get file size pf->file_size = 0; pf->seekable = 0; #ifdef _WIN32 // in Windows, don't try to detect seeking support for stdin if (fp != stdin) pf->seekable = !fseek(fp, 0, SEEK_END); #else pf->seekable = !fseek(fp, 0, SEEK_END); #endif if (pf->seekable) { // TODO: portable 64-bit ftell long fs = ftell(fp); // ftell should return an error if value cannot fit in return type if (fs < 0) { fprintf(stderr, "Warning, unsupported file size.\n"); pf->file_size = 0; } else { pf->file_size = (uint64_t)fs; } fseek(fp, 0, SEEK_SET); } pf->filepos = 0; if (byteio_init(&pf->io, fp)) { fprintf(stderr, "error initializing byte buffer\n"); return -1; } // detect file format if not specified by the user pcmfile_register_all_formats(); if (pf->file_format == PCM_FORMAT_UNKNOWN) { uint8_t probe_data[12]; byteio_peek(probe_data, 12, &pf->io); pf->pcm_format = pcmfile_probe_format(probe_data, 12); pf->file_format = pf->pcm_format->format; } else { pf->pcm_format = pcmfile_find_format(pf->file_format); } if (pf->pcm_format == NULL) { fprintf(stderr, "unable to detect file format\n"); return -1; } // initialize format if (pf->pcm_format->init && pf->pcm_format->init(pf)) return -1; return 0; } void pcmfile_close(PcmFile *pf) { byteio_close(&pf->io); } void pcmfile_print(PcmFile *pf, FILE *st) { const char *type, *chan, *fmt, *order; if (st == NULL || pf == NULL) return; type = "?"; chan = "?-channel"; fmt = "unknown"; order = ""; if (pf->sample_type == PCM_SAMPLE_TYPE_INT) { if (pf->source_format == PCM_SAMPLE_FMT_U8) type = "Unsigned"; else type = "Signed"; } else if (pf->sample_type == PCM_SAMPLE_TYPE_FLOAT) { type = "Floating-point"; } else { type = "[unsupported type]"; } if (pf->ch_mask & 0x08) { switch (pf->channels-1) { case 1: chan = "1.1-channel"; break; case 2: chan = "2.1-channel"; break; case 3: chan = "3.1-channel"; break; case 4: chan = "4.1-channel"; break; case 5: chan = "5.1-channel"; break; default: chan = "multi-channel with LFE"; break; } } else { switch (pf->channels) { case 1: chan = "mono"; break; case 2: chan = "stereo"; break; case 3: chan = "3-channel"; break; case 4: chan = "4-channel"; break; case 5: chan = "5-channel"; break; case 6: chan = "6-channel"; break; default: chan = "multi-channel"; break; } } if (pf->pcm_format) fmt = pf->pcm_format->long_name; if (pf->source_format > PCM_SAMPLE_FMT_S8) { switch (pf->order) { case PCM_BYTE_ORDER_LE: order = "little-endian"; break; case PCM_BYTE_ORDER_BE: order = "big-endian"; break; } } else { order = "\b"; } fprintf(st, "%s %s %d-bit %s %d Hz %s\n", fmt, type, pf->bit_width, order, pf->sample_rate, chan); } int pcm_get_default_ch_mask(int channels) { static const int nch_to_mask[6] = { 0x04, // mono (1/0) 0x03, // stereo (2/0) 0x103, // 3.0 surround (2/1) 0x107, // 3/1 surround (3/1) 0x37, // 5.0 surround (3/2) 0x3F // 5.1 surround (3/2+LFE) }; if (channels < 1 || channels > 6) return 0; return nch_to_mask[channels-1]; } aften/pcm/pcmfile.h000066400000000000000000000133441132016273200145240ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * Copyright (c) 2007 Justin Ruggles * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file pcmfile.h * raw PCM file i/o header */ #ifndef PCMFILE_H #define PCMFILE_H #include "common.h" #include "byteio.h" #include "formats.h" /* "whence" values for seek functions */ #define PCM_SEEK_SET 0 #define PCM_SEEK_CUR 1 #define PCM_SEEK_END 2 /* maximum single read size: 5 sec at 48kHz */ #define PCM_MAX_READ 240000 /* maximum number of supported channels */ #define PCM_MAX_CHANNELS 6 /* supported TWOCC WAVE formats */ #define WAVE_FORMAT_PCM 0x0001 #define WAVE_FORMAT_IEEEFLOAT 0x0003 #define WAVE_FORMAT_EXTENSIBLE 0xFFFE /* raw audio sample types */ enum PcmSampleType { PCM_SAMPLE_TYPE_INT = 0, PCM_SAMPLE_TYPE_FLOAT }; /* supported raw audio sample formats */ enum PcmSampleFormat { PCM_SAMPLE_FMT_UNKNOWN = -1, PCM_SAMPLE_FMT_U8 = 0, PCM_SAMPLE_FMT_S8, PCM_SAMPLE_FMT_S16, PCM_SAMPLE_FMT_S20, PCM_SAMPLE_FMT_S24, PCM_SAMPLE_FMT_S32, PCM_SAMPLE_FMT_FLT, PCM_SAMPLE_FMT_DBL }; /* byte orders */ enum PcmByteOrder { PCM_BYTE_ORDER_LE = 0, PCM_BYTE_ORDER_BE = 1 }; /* main decoder context */ typedef struct PcmFile { /** Format conversion function */ void (*fmt_convert)(void *dest_v, void *src_v, int n); ByteIOContext io; ///< input buffer uint64_t filepos; ///< current file position int seekable; ///< indicates if input stream is seekable int read_to_eof; ///< indicates that data is to be read until EOF uint64_t file_size; ///< total file size, if known uint64_t data_start; ///< byte position for start of data uint64_t data_size; ///< data size, in bytes uint64_t samples; ///< total number of audio samples int sample_type; ///< sample type (integer or floating-point) int file_format; ///< file format (raw, wav, etc...) PcmFormat *pcm_format; ///< functions and descriptions for file format int order; ///< sample byte order int channels; ///< number of channels uint32_t ch_mask; ///< channel mask, indicates speaker locations int sample_rate; ///< audio sampling frequency int block_align; ///< bytes in each sample, for all channels int bit_width; ///< bits-per-sample enum PcmSampleFormat source_format; ///< sample type in the input file enum PcmSampleFormat read_format; ///< sample type to convert to when reading int internal_fmt; ///< internal format (e.g. WAVE wFormatTag) } PcmFile; /** * Initializes PcmFile structure using the given input file pointer. * Examines the header (if present) to get audio information and has the file * pointer aligned at start of data when it exits. * Returns non-zero value if an error occurs. */ extern int pcmfile_init(PcmFile *pf, FILE *fp, enum PcmSampleFormat read_format, int file_format); /** * Frees memory from internal buffer. */ extern void pcmfile_close(PcmFile *pf); /** * Sets the source sample format */ extern void pcmfile_set_source_format(PcmFile *pf, enum PcmSampleFormat fmt); /** * Sets source audio information */ extern void pcmfile_set_source_params(PcmFile *pf, int ch, enum PcmSampleFormat fmt, int order, int sr); /** * Sets the requested read format */ extern void pcmfile_set_read_format(PcmFile *pf, enum PcmSampleFormat read_format); /** * Prints out a description of the pcm format to the specified * output stream. */ extern void pcmfile_print(PcmFile *pf, FILE *st); /** * Returns a default channel mask value based on the number of channels */ extern int pcm_get_default_ch_mask(int channels); /** * Reads audio samples to the output buffer. * Output is channel-interleaved, native byte order. * Only up to PCM_MAX_READ samples can be read in one call. * The output sample format depends on the value of pf->read_format. * Returns number of samples read or -1 on error. */ extern int pcmfile_read_samples(PcmFile *pf, void *buffer, int num_samples); /** * Seeks to byte offset within file. * Limits the seek position or offset to signed 32-bit. * It also does slower forward seeking for streaming input. */ extern int pcmfile_seek_set(PcmFile *pf, uint64_t dest); /** * Seeks to sample offset. * Syntax works like fseek. use PCM_SEEK_SET, PCM_SEEK_CUR, or PCM_SEEK_END * for the whence value. Returns -1 on error, 0 otherwise. */ extern int pcmfile_seek_samples(PcmFile *pf, int64_t offset, int whence); /** * Seeks to time offset, in milliseconds, based on the audio sample rate. * Syntax works like fseek. use PCM_SEEK_SET, PCM_SEEK_CUR, or PCM_SEEK_END * for the whence value. Returns -1 on error, 0 otherwise. */ extern int pcmfile_seek_time_ms(PcmFile *pf, int64_t offset, int whence); /** * Returns the current stream position, in samples. * Returns -1 on error. */ extern uint64_t pcmfile_position(PcmFile *pf); /** * Returns the current stream position, in milliseconds. * Returns -1 on error. */ extern uint64_t pcmfile_position_time_ms(PcmFile *pf); #endif /* PCMFILE_H */ aften/pcm/raw.c000066400000000000000000000026321132016273200136670ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * Copyright (c) 2006 Justin Ruggles * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file raw.c * Raw file format */ #include "pcm.h" static int raw_probe(uint8_t *data, int size) { if (data == NULL || size < 0) return 0; return 1; } static int raw_init(PcmFile *pf) { pf->data_size = 0; pf->data_start = 0; if (pf->seekable && pf->file_size > 0) { pf->data_size = pf->file_size; } pf->read_to_eof = 1; pcmfile_set_source_params(pf, 1, PCM_SAMPLE_FMT_S16, PCM_BYTE_ORDER_LE, 48000); return 0; } PcmFormat raw_format = { "raw", "Raw PCM", PCM_FORMAT_RAW, raw_probe, raw_init, NULL }; aften/pcm/wav.c000066400000000000000000000154661132016273200137040ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * Copyright (c) 2006 Justin Ruggles * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file wav.c * WAV file format */ #include "pcm.h" /* chunk id's */ #define RIFF_ID 0x46464952 #define WAVE_ID 0x45564157 #define FMT__ID 0x20746D66 #define DATA_ID 0x61746164 /** * Reads a 4-byte little-endian word from the input stream */ static inline uint32_t read4le(PcmFile *pf) { uint32_t x; if (byteio_read(&x, 4, &pf->io) != 4) return 0; pf->filepos += 4; return le2me_32(x); } /** * Reads a 2-byte little-endian word from the input stream */ static inline uint16_t read2le(PcmFile *pf) { uint16_t x; if (byteio_read(&x, 2, &pf->io) != 2) return 0; pf->filepos += 2; return le2me_16(x); } static int wave_probe(uint8_t *data, int size) { int id; if (!data || size < 12) return 0; id = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); if (id != RIFF_ID) return 0; id = data[8] | (data[9] << 8) | (data[10] << 16) | (data[11] << 24); if(id != WAVE_ID) return 0; return 100; } static int wave_init(PcmFile *pf) { int id, found_data, found_fmt, chunksize; enum PcmSampleFormat src_fmt; // read RIFF id. ignore size. id = read4le(pf); if (id != RIFF_ID) { fprintf(stderr, "invalid RIFF id in wav header\n"); return -1; } read4le(pf); // read WAVE id. ignore size. id = read4le(pf); if (id != WAVE_ID) { fprintf(stderr, "invalid WAVE id in wav header\n"); return -1; } // read all header chunks. skip unknown chunks. found_data = found_fmt = 0; while (!found_data) { id = read4le(pf); chunksize = read4le(pf); switch (id) { case FMT__ID: if (chunksize < 16) { fprintf(stderr, "invalid fmt chunk in wav header\n"); return -1; } pf->internal_fmt = read2le(pf); pf->channels = read2le(pf); pf->ch_mask = pcm_get_default_ch_mask(pf->channels); pf->sample_rate = read4le(pf); read4le(pf); read2le(pf); pf->bit_width = read2le(pf); pf->block_align = MAX(1, ((pf->bit_width + 7) >> 3) * pf->channels); pf->order = PCM_BYTE_ORDER_LE; chunksize -= 16; // WAVE_FORMAT_EXTENSIBLE data if (pf->internal_fmt == WAVE_FORMAT_EXTENSIBLE && chunksize >= 10) { read4le(pf); // skip CbSize and ValidBitsPerSample pf->ch_mask = read4le(pf); pf->internal_fmt = read2le(pf); chunksize -= 10; } // set sample type based on wFormatTag if (pf->internal_fmt == WAVE_FORMAT_IEEEFLOAT) { pf->sample_type = PCM_SAMPLE_TYPE_FLOAT; } else if (pf->internal_fmt == WAVE_FORMAT_PCM) { pf->sample_type = PCM_SAMPLE_TYPE_INT; } else { fprintf(stderr, "unsupported wFormatTag: 0x%02X\n", pf->internal_fmt); return -1; } // validate format parameters if (pf->channels == 0) { fprintf(stderr, "invalid number of channels in wav header\n"); return -1; } if (pf->sample_rate == 0) { fprintf(stderr, "invalid sample rate in wav header\n"); return -1; } if (pf->bit_width == 0) { fprintf(stderr, "invalid sample bit width in wav header\n"); return -1; } // skip any leftover bytes in fmt chunk if (pcmfile_seek_set(pf, pf->filepos + chunksize)) { fprintf(stderr, "error seeking in wav file\n"); return -1; } found_fmt = 1; break; case DATA_ID: if (!found_fmt) return -1; if (chunksize == 0) pf->read_to_eof = 1; pf->data_size = chunksize; pf->data_start = pf->filepos; if (pf->seekable && pf->file_size > 0) { // limit data size to end-of-file if (pf->data_size > 0) pf->data_size = MIN(pf->data_size, pf->file_size - pf->data_start); else pf->data_size = pf->file_size - pf->data_start; } pf->samples = (pf->data_size / pf->block_align); found_data = 1; break; default: // skip unknown chunk if (chunksize > 0 && pcmfile_seek_set(pf, pf->filepos + chunksize)) { fprintf(stderr, "error seeking in wav file\n"); return -1; } } } // set audio data format based on bit depth and sample type src_fmt = PCM_SAMPLE_FMT_UNKNOWN; switch (pf->bit_width) { case 8: src_fmt = PCM_SAMPLE_FMT_U8; break; case 16: src_fmt = PCM_SAMPLE_FMT_S16; break; case 20: src_fmt = PCM_SAMPLE_FMT_S20; break; case 24: src_fmt = PCM_SAMPLE_FMT_S24; break; case 32: if (pf->sample_type == PCM_SAMPLE_TYPE_FLOAT) src_fmt = PCM_SAMPLE_FMT_FLT; else if (pf->sample_type == PCM_SAMPLE_TYPE_INT) src_fmt = PCM_SAMPLE_FMT_S32; break; case 64: if (pf->sample_type == PCM_SAMPLE_TYPE_FLOAT) { src_fmt = PCM_SAMPLE_FMT_DBL; } else { fprintf(stderr, "64-bit integer samples not supported\n"); return -1; } break; } pcmfile_set_source_format(pf, src_fmt); return 0; } PcmFormat wave_format = { "wave", "Microsoft WAVE", PCM_FORMAT_WAVE, wave_probe, wave_init, NULL }; aften/util/000077500000000000000000000000001132016273200131255ustar00rootroot00000000000000aften/util/wavfilter.c000066400000000000000000000115741132016273200153040ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * Copyright (c) 2006 Justin Ruggles * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file wavfilter.c * Console WAV File Filter Utility */ #include "common.h" #include "pcm.h" #include "filter.h" static void wav_filter(FLOAT *samples, int ch, int n, FilterContext *f) { FLOAT *samples2_buffer = malloc(ch * n * sizeof(FLOAT)); FLOAT **samples2 = malloc(ch * sizeof(FLOAT*)); FLOAT *tmp = malloc(n * sizeof(FLOAT)); int j, i, c; for (i = 0, j = 0; i < ch; i++, j += n) samples2[i] = samples2_buffer + j; for (i = 0, j = 0; i < n; i++) { for (c = 0; c < ch; c++, j++) samples2[c][i] = samples[j]; } for (c = 0; c < ch; c++) { memcpy(tmp, samples2[c], n * sizeof(FLOAT)); filter_run(&f[c], samples2[c], tmp, n); } for (i = 0, j = 0; i < n; i++) { for (c = 0; c < ch; c++, j++) { samples[j] = samples2[c][i]; if (samples[j] > 1.0) samples[j] = 1.0; if (samples[j] < -1.0) samples[j] = -1.0; } } free(tmp); free(samples2_buffer); } static void write2le(uint16_t v, FILE *ofp) { fputc((v ) & 0xFF, ofp); fputc((v >> 8) & 0xFF, ofp); } static void write4le(uint32_t v, FILE *ofp) { fputc((v ) & 0xFF, ofp); fputc((v >> 8) & 0xFF, ofp); fputc((v >> 16) & 0xFF, ofp); fputc((v >> 24) & 0xFF, ofp); } static void output_wav_header(FILE *ofp, PcmFile *wf) { fwrite("RIFF", 1, 4, ofp); write4le(((uint32_t)wf->data_size + 36), ofp); fwrite("WAVE", 1, 4, ofp); fwrite("fmt ", 1, 4, ofp); write4le(16, ofp); write2le(WAVE_FORMAT_PCM, ofp); write2le(wf->channels, ofp); write4le(wf->sample_rate, ofp); write4le(wf->sample_rate * wf->channels * 2, ofp); write2le(wf->channels * 2, ofp); write2le(16, ofp); fwrite("data", 1, 4, ofp); write4le((uint32_t)wf->data_size, ofp); } static void output_wav_data(FILE *ofp, FLOAT *samples, int ch, int n) { int16_t s16[1]; uint16_t *u16 = (uint16_t *)s16; int i; for (i = 0; i < n*ch; i++) { s16[0] = (int16_t)(samples[i] * 32767.0); write2le(*u16, ofp); } } static const char *usage = "usage: wavfilter "; int main(int argc, char **argv) { FILE *ifp, *ofp; PcmFile pf; FLOAT *buf; int frame_size; int nr; int i; FilterContext f[6]; int ftype=0; enum PcmSampleFormat read_format; if (argc != 5) { fprintf(stderr, "\n%s\n\n", usage); exit(1); } if (!strncmp(argv[1], "lp", 3)) { ftype = FILTER_TYPE_LOWPASS; } else if (!strncmp(argv[1], "hp", 3)) { ftype = FILTER_TYPE_HIGHPASS; } else { fprintf(stderr, "\n%s\n\n", usage); exit(1); } ifp = fopen(argv[3], "rb"); if (!ifp) { fprintf(stderr, "cannot open input file\n"); exit(1); } ofp = fopen(argv[4], "wb"); if (!ofp) { fprintf(stderr, "cannot open output file\n"); exit(1); } #ifdef CONFIG_DOUBLE read_format = PCM_SAMPLE_FMT_DBL; #else read_format = PCM_SAMPLE_FMT_FLT; #endif if (pcmfile_init(&pf, ifp, read_format, PCM_FORMAT_WAVE)) { fprintf(stderr, "error initializing wav reader\n\n"); exit(1); } output_wav_header(ofp, &pf); for (i = 0; i < pf.channels; i++) { int cutoff; f[i].type = (enum FilterType)ftype; f[i].cascaded = 1; cutoff = atoi(argv[2]); f[i].cutoff = (FLOAT)cutoff; f[i].samplerate = (FLOAT)pf.sample_rate; if (filter_init(&f[i], FILTER_ID_BUTTERWORTH_II)) { fprintf(stderr, "error initializing filter\n"); exit(1); } } frame_size = 512; buf = calloc(frame_size * pf.channels, sizeof(FLOAT)); nr = pcmfile_read_samples(&pf, buf, frame_size); while (nr > 0) { wav_filter(buf, pf.channels, nr, f); output_wav_data(ofp, buf, pf.channels, nr); nr = pcmfile_read_samples(&pf, buf, frame_size); } for (i = 0; i < pf.channels; i++) filter_close(&f[i]); free(buf); pcmfile_close(&pf); fclose(ifp); fclose(ofp); return 0; } aften/util/wavinfo.c000066400000000000000000000307701132016273200147510ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * Copyright (c) 2006 Justin Ruggles * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file wavinfo.c * Console WAV File Info Utility */ #include "common.h" #ifdef _WIN32 #include #include #endif #include "pcm.h" static char * get_format_name(int id) { if (id < 0x0000 || id > 0xFFFF) return NULL; switch (id) { case 0x0000: return "Microsoft Unknown Wave Format"; case 0x0001: return "Microsoft PCM"; case 0x0002: return "Microsoft ADPCM"; case 0x0003: return "IEEE Float"; case 0x0004: return "Compaq Computer VSELP"; case 0x0005: return "IBM CVSD"; case 0x0006: return "Microsoft A-Law"; case 0x0007: return "Microsoft mu-Law"; case 0x0008: return "Microsoft DTS"; case 0x0009: return "Microsoft DRM Encrypted Audio"; case 0x000A: return "Windows Media Audio 9 Voice"; case 0x000B: return "Windows Media RT Voice"; case 0x0010: return "OKI ADPCM"; case 0x0011: return "Intel DVI/IMA ADPCM"; case 0x0012: return "Videologic MediaSpace ADPCM"; case 0x0013: return "Sierra ADPCM"; case 0x0014: return "Antex G.723 ADPCM"; case 0x0015: return "DSP Solutions DigiSTD"; case 0x0016: return "DSP Solutions DigiFIX"; case 0x0017: return "Dialogic OKI ADPCM"; case 0x0018: return "MediaVision ADPCM"; case 0x0019: return "Hewlett-Packard CU"; case 0x0020: return "Yamaha ADPCM"; case 0x0021: return "Speech Compression Sonarc"; case 0x0022: return "DSP Group TrueSpeech"; case 0x0023: return "Echo Speech EchoSC1"; case 0x0024: return "Audiofile AF36"; case 0x0025: return "Audio Processing Technology APTX"; case 0x0026: return "AudioFile AF10"; case 0x0027: return "Prosody 1612"; case 0x0028: return "LRC"; case 0x0030: return "Dolby AC2"; case 0x0031: return "Microsoft GSM 6.10"; case 0x0032: return "MSNAudio"; case 0x0033: return "Antex ADPCME"; case 0x0034: return "Control Resources VQLPC"; case 0x0035: return "DigiREAL"; case 0x0036: return "DigiADPCM"; case 0x0037: return "Control Resources CR10"; case 0x0038: return "Natural MicroSystems VBXADPCM"; case 0x0039: return "Crystal IMA ADPCM"; case 0x003A: return "EchoSC3"; case 0x003B: return "Rockwell ADPCM"; case 0x003C: return "Rockwell Digit LK"; case 0x003D: return "Xebec"; case 0x0040: return "Antex Electronics G.721 ADPCM"; case 0x0041: return "G.728 CELP"; case 0x0042: return "MS G.723"; case 0x0043: return "MS G.723.1"; case 0x0044: return "MS G.729"; case 0x0045: return "SP G.726"; case 0x0050: return "MPEG Layer-2 or Layer-1"; case 0x0052: return "RT24"; case 0x0053: return "PAC"; case 0x0055: return "MPEG Layer-3"; case 0x0059: return "Lucent G.723"; case 0x0060: return "Cirrus"; case 0x0061: return "ESPCM"; case 0x0062: return "Voxware"; case 0x0063: return "Canopus Atrac"; case 0x0064: return "G.726 ADPCM"; case 0x0065: return "G.722 ADPCM"; case 0x0066: return "DSAT"; case 0x0067: return "DSAT Display"; case 0x0069: return "Voxware Byte Aligned"; case 0x0070: return "Voxware AC8"; case 0x0071: return "Voxware AC10"; case 0x0072: return "Voxware AC16"; case 0x0073: return "Voxware AC20"; case 0x0074: return "Voxware MetaVoice"; case 0x0075: return "Voxware MetaSound"; case 0x0076: return "Voxware RT29HW"; case 0x0077: return "Voxware VR12"; case 0x0078: return "Voxware VR18"; case 0x0079: return "Voxware TQ40"; case 0x0080: return "Softsound"; case 0x0081: return "Voxware TQ60"; case 0x0082: return "MSRT24"; case 0x0083: return "G.729A"; case 0x0084: return "MVI MV12"; case 0x0085: return "DF G.726"; case 0x0086: return "DF GSM610"; case 0x0088: return "ISIAudio"; case 0x0089: return "Onlive"; case 0x0091: return "SBC24"; case 0x0092: return "Dolby AC3 SPDIF"; case 0x0093: return "MediaSonic G.723"; case 0x0094: return "Aculab PLC Prosody 8kbps"; case 0x0097: return "ZyXEL ADPCM"; case 0x0098: return "Philips LPCBB"; case 0x0099: return "Packed"; case 0x00FF: return "AAC"; case 0x0100: return "Rhetorex ADPCM"; case 0x0101: return "IBM mu-law"; case 0x0102: return "IBM A-law"; case 0x0103: return "IBM AVC ADPCM"; case 0x0111: return "Vivo G.723"; case 0x0112: return "Vivo Siren"; case 0x0123: return "Digital G.723"; case 0x0125: return "Sanyo LD ADPCM"; case 0x0130: return "Sipro Lab Telecom ACELP NET / RealAudio 4.0/5.0)"; case 0x0131: return "Sipro Lab Telecom ACELP 4800"; case 0x0132: return "Sipro Lab Telecom ACELP 8V3"; case 0x0133: return "Sipro Lab Telecom G.729"; case 0x0134: return "Sipro Lab Telecom G.729A"; case 0x0135: return "Sipro Lab Telecom Kelvin"; case 0x0140: return "Windows Media Video V8"; case 0x0150: return "Qualcomm PureVoice"; case 0x0151: return "Qualcomm HalfRate"; case 0x0155: return "Ring Zero Systems TUB GSM"; case 0x0160: return "Microsoft Audio 1"; case 0x0161: return "Windows Media 7/8/9"; case 0x0162: return "Windows Media 9 Professional"; case 0x0163: return "Windows Media 9 Lossless"; case 0x0164: return "Windows Media Professional over S/PDIF"; case 0x0180: return "MPEG-2 AAC"; case 0x0190: return "DTS"; case 0x0200: return "Creative Labs ADPCM"; case 0x0202: return "Creative Labs FastSpeech8"; case 0x0203: return "Creative Labs FastSpeech10"; case 0x0210: return "UHER Informatic GmbH ADPCM"; case 0x0215: return "Ulead DV Audio NTSC"; case 0x0216: return "Ulead DV Audio PAL"; case 0x0220: return "Quarterdeck"; case 0x0230: return "I-link Worldwide VC"; case 0x0240: return "Aureal RAW Sport"; case 0x0250: return "Interactive Products HSX"; case 0x0251: return "Interactive Products RPELP"; case 0x0260: return "Consistent Software CS2"; case 0x0270: return "Sony SCX / RealAudio 8.0"; case 0x0271: return "Sony SCY"; case 0x0272: return "Sony ATRAC3"; case 0x0273: return "Sony SPC"; case 0x0300: return "Fujitsu FM Towns Snd"; case 0x0400: return "BTV Digital"; case 0x0401: return "Intel Music Coder"; case 0x0450: return "QDesign Music"; case 0x0680: return "VME VMPCM"; case 0x0681: return "AT&T Labs TPC"; case 0x08AE: return "ClearJump LiteWave"; case 0x1000: return "Olivetti GSM"; case 0x1001: return "Olivetti ADPCM"; case 0x1002: return "Olivetti CELP"; case 0x1003: return "Olivetti SBC"; case 0x1004: return "Olivetti OPR"; case 0x1100: return "L&H Codec"; case 0x1101: return "L&H CELP"; case 0x1102: return "L&H SBC 0x1102"; case 0x1103: return "L&H SBC 0x1103"; case 0x1104: return "L&H SBC 0x1104"; case 0x1400: return "Norris"; case 0x1401: return "AT&T ISIAudio"; case 0x1500: return "Soundspace Music Compression"; case 0x181C: return "VoxWare RT24 Speech"; case 0x1971: return "Sonic Foundry Perfect Clarity Audio (PCA)"; case 0x1FC4: return "NCT Soft ALF2CD"; case 0x2000: return "Dolby AC3"; case 0x2001: return "Dolby DTS"; case 0x2002: return "RealAudio 1.0 (14.4K)"; case 0x2003: return "RealAudio 2.0 (28.8K)"; case 0x2004: return "RealAudio G2 (Cook)"; case 0x2005: return "RealAudio 3.0 (DolbyNet AC3)"; case 0x2006: return "RealAudio 10.0 (LC-AAC)"; case 0x2007: return "RealAudio 10.0 (HE-AAC)"; case 0x2048: return "Sonic"; case 0x4143: return "Divio AAC"; case 0x4201: return "Nokia AMR"; case 0x566F: return "Vorbis"; case 0x5756: return "WavPack"; case 0x674F: return "Ogg Vorbis 1"; case 0x6750: return "Ogg Vorbis 2"; case 0x6751: return "Ogg Vorbis 3"; case 0x676F: return "Ogg Vorbis 1+"; case 0x6770: return "Ogg Vorbis 2+"; case 0x6771: return "Ogg Vorbis 3+"; case 0x7A21: return "Adaptive Multirate"; case 0x7A22: return "Adaptive Multirate w/ silence detection"; case 0x706D: return "AAC"; case 0x77A1: return "TTA"; case 0xA106: return "MPEG-4 AAC"; case 0xA109: return "Speex"; case 0xF1AC: return "FLAC"; case 0xFFFE: return "{ Extensible }"; case 0xFFFF: return "{ Development }"; default: return NULL; } } typedef struct WavInfo { char *fname; PcmFile pf; } WavInfo; static void wavinfo_print(WavInfo *wi) { char *type; int64_t leftover; float playtime; PcmFile *wf = &wi->pf; type = get_format_name(wf->internal_fmt); printf("\n=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n"); printf("File:\n"); printf(" Name: %s\n", wi->fname); if (wf->seekable) { printf(" File Size: %"PRIu64"\n", wf->file_size); } else { printf(" File Size: unknown\n"); } printf("Format:\n"); if (type == NULL) { printf(" Type: unknown - 0x%04X\n", wf->internal_fmt); } else { printf(" Type: %s\n", type); } printf(" Channels: %d\n", wf->channels); printf(" Sample Rate: %d Hz\n", wf->sample_rate); printf(" Avg bytes/sec: %d\n", wf->block_align * wf->sample_rate); printf(" Block Align: %d bytes\n", wf->block_align); printf(" Bit Width: %d\n", wf->bit_width); if (wf->ch_mask > 0) { printf(" Channel Mask: 0x%03"PRIX32"\n", wf->ch_mask); } printf("Data:\n"); printf(" Start: %"PRIu64"\n", wf->data_start); printf(" Data Size: %"PRIu64"\n", wf->data_size); leftover = ((int64_t)(wf->file_size)) - wf->data_size - wf->data_start; if (leftover < 0) { if (!wf->seekable) { printf(" [ warning! unable to verify true data size ]\n"); } else { printf(" [ warning! reported data size is larger than file size ]\n"); } } else if (leftover > 0) { printf(" Leftover: %"PRId64" bytes\n", leftover); } if (wf->internal_fmt == 0x0001 || wf->internal_fmt == 0x0003) { playtime = (float)wf->samples / (float)wf->sample_rate; printf(" Samples: %"PRIu64"\n", wf->samples); printf(" Playing Time: %0.2f sec\n", playtime); } else { printf(" Samples: unknown\n"); printf(" Playing Time: unknown\n"); } printf("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n\n"); } static void wavfile_error(char *msg) { if (msg != NULL) { fprintf(stderr, "%s\n", msg); } exit(1); } int main(int argc, char **argv) { FILE *fp; WavInfo wi; PcmFile *pf = &wi.pf; /* initialize WavInfo to zero */ memset(&wi, 0, sizeof(WavInfo)); /* open file */ if (argc > 2) { wavfile_error("\nusage: wavinfo [test.wav]\n"); } if (argc == 2) { wi.fname = argv[1]; fp = fopen(wi.fname, "rb"); } else { wi.fname = "[stdin]"; #ifdef _WIN32 _setmode(_fileno(stdin), _O_BINARY); #endif fp = stdin; } if (!fp) wavfile_error("cannot open file"); pcmfile_init(pf, fp, PCM_SAMPLE_FMT_UNKNOWN, PCM_FORMAT_WAVE); /* print info */ wavinfo_print(&wi); pcmfile_close(pf); fclose(fp); return 0; } aften/util/wavrms.c000066400000000000000000000107631132016273200146170ustar00rootroot00000000000000/** * Aften: A/52 audio encoder * Copyright (c) 2006 Justin Ruggles * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file wavrms.c * Console WAV File RMS/Dialog Normalization Utility */ #include "common.h" #ifdef _WIN32 #include #include #endif #include "pcm.h" static int calculate_rms(FLOAT *samples, int ch, int n) { FLOAT rms_all, rms_left, rms_right; int i; // Calculate RMS values if (ch == 1) { rms_all = 0.0; for (i = 0; i < n; i++) { rms_all += (samples[i] * samples[i]); } rms_all /= n; } else { rms_left = rms_right = 0.0; for (i = 0; i < n*ch; i += ch) { rms_left += (samples[i ] * samples[i ]); rms_right += (samples[i+1] * samples[i+1]); } rms_left /= n; rms_right /= n; rms_all = (rms_left + rms_right) / FCONST(2.0); } // Convert to dB rms_all = FCONST(10.0) * AFT_LOG10(rms_all + FCONST(1e-10)); return -((int)(rms_all + FCONST(0.5))); } static void print_intro(FILE *stream) { fprintf(stream, "\nWavRMS: utility program to calculate AC-3 dialnorm.\n" "(c) 2006-2007 Justin Ruggles, et al.\n\n"); } static void print_usage(FILE *stream) { fprintf(stream, "usage: wavrms [ []]\n" " use '-' to input from stdin.\n" " unit for start and end is seconds.\n" "\n"); } int main(int argc, char **argv) { FILE *fp; PcmFile pf; FLOAT *buf; uint32_t start_sec, end_sec; int frame_size, nr, rms; uint64_t avg_rms, avg_cnt; uint64_t time_ms; enum PcmSampleFormat read_format; /* open file */ if (argc < 2 || argc > 4) { print_intro(stderr); print_usage(stderr); exit(1); } print_intro(stdout); if (argc == 2 && !strncmp(argv[1], "-h", 3)) { print_usage(stdout); return 0; } start_sec = 0; end_sec = UINT32_MAX; if (argc == 3 || argc == 4) { start_sec = MAX(atoi(argv[2]), 0); if (argc == 4) { end_sec = MAX(atoi(argv[3]), 0); } if (end_sec <= start_sec) { fprintf(stderr, "invalid time range\n"); exit(1); } } if (!strncmp(argv[1], "-", 2)) { #ifdef _WIN32 _setmode(_fileno(stdin), _O_BINARY); #endif fp = stdin; } else { fp = fopen(argv[1], "rb"); } if (!fp) { fprintf(stderr, "cannot open file\n"); exit(1); } #ifdef CONFIG_DOUBLE read_format = PCM_SAMPLE_FMT_DBL; #else read_format = PCM_SAMPLE_FMT_FLT; #endif if (pcmfile_init(&pf, fp, read_format, PCM_FORMAT_WAVE)) { fprintf(stderr, "error initializing wav reader\n\n"); exit(1); } frame_size = pf.sample_rate * 50 / 1000; // seek to start of time range pcmfile_seek_time_ms(&pf, start_sec*1000, PCM_SEEK_SET); buf = calloc(frame_size * pf.channels, sizeof(FLOAT)); avg_rms = 31; avg_cnt = 1; time_ms = pcmfile_position_time_ms(&pf); nr = pcmfile_read_samples(&pf, buf, frame_size); while (nr > 0) { // check for end of time range if (time_ms > (end_sec*1000)) { break; } rms = calculate_rms(buf, pf.channels, nr); // use a reasonable dialog range if(rms < 40 && rms > 15) { avg_rms += rms; avg_cnt++; } time_ms = pcmfile_position_time_ms(&pf); nr = pcmfile_read_samples(&pf, buf, frame_size); } avg_rms /= avg_cnt; time_ms /= 1000; fprintf(stdout, "Time Range: %"PRIu64" to %"PRIu64" sec\n", MIN(start_sec, time_ms), time_ms); fprintf(stdout, "Dialnorm: -%d dB\n\n", (int)MIN(avg_rms, 31)); free(buf); pcmfile_close(&pf); fclose(fp); return 0; }