diff --git a/Cog.xcodeproj/project.pbxproj b/Cog.xcodeproj/project.pbxproj index f59f28ade..a3ac102f6 100644 --- a/Cog.xcodeproj/project.pbxproj +++ b/Cog.xcodeproj/project.pbxproj @@ -134,6 +134,7 @@ 836FB5A718206F2500B3AD2D /* Hively.bundle in CopyFiles */ = {isa = PBXBuildFile; fileRef = 836FB5471820538800B3AD2D /* Hively.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; 8370D73D277419F700245CE0 /* SQLiteStore.m in Sources */ = {isa = PBXBuildFile; fileRef = 8370D73C277419F700245CE0 /* SQLiteStore.m */; }; 8370D73F2775AE1300245CE0 /* libsqlite3.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 8370D73E2775AE1300245CE0 /* libsqlite3.tbd */; }; + 8372C93D27C7895300E250C9 /* MAD.bundle in CopyFiles */ = {isa = PBXBuildFile; fileRef = 8372C93027C785BE00E250C9 /* MAD.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 8377C66327B8CF6300E8BC0F /* SpectrumView.m in Sources */ = {isa = PBXBuildFile; fileRef = 8377C66127B8CF6300E8BC0F /* SpectrumView.m */; }; 8377C6B927B900F000E8BC0F /* SpectrumItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 8377C6B827B900F000E8BC0F /* SpectrumItem.m */; }; 8381A09227C5F72F00A1C530 /* SHA256Digest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8381A09127C5F72F00A1C530 /* SHA256Digest.m */; }; @@ -518,6 +519,20 @@ remoteGlobalIDString = 836FB52C1820538700B3AD2D; remoteInfo = Hively; }; + 8372C92F27C785BE00E250C9 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 8372C92A27C785BD00E250C9 /* MAD.xcodeproj */; + proxyType = 2; + remoteGlobalIDString = 8372C92327C785BD00E250C9; + remoteInfo = MAD; + }; + 8372C93B27C7893100E250C9 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 8372C92A27C785BD00E250C9 /* MAD.xcodeproj */; + proxyType = 1; + remoteGlobalIDString = 8372C92227C785BD00E250C9; + remoteInfo = MAD; + }; 8375B36117FFEF010092A79F /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 8359FF2C17FEF35C0060F3ED /* ArchiveSource.xcodeproj */; @@ -670,6 +685,7 @@ dstPath = ""; dstSubfolderSpec = 13; files = ( + 8372C93D27C7895300E250C9 /* MAD.bundle in CopyFiles */, 83489C6B2782F78700BDCEA2 /* libvgmPlayer.bundle in CopyFiles */, 83293070277886250010C07E /* OpenMPTOld.bundle in CopyFiles */, 834D794020E4EFEF00C4A5CC /* VorbisPlugin.bundle in CopyFiles */, @@ -941,6 +957,7 @@ 8370D739277419D200245CE0 /* SQLiteStore.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SQLiteStore.h; sourceTree = ""; }; 8370D73C277419F700245CE0 /* SQLiteStore.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SQLiteStore.m; sourceTree = ""; }; 8370D73E2775AE1300245CE0 /* libsqlite3.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.tbd; path = usr/lib/libsqlite3.tbd; sourceTree = SDKROOT; }; + 8372C92A27C785BD00E250C9 /* MAD.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = MAD.xcodeproj; path = Plugins/MAD/MAD.xcodeproj; sourceTree = ""; }; 8375B05117FFEA400092A79F /* OpusPlugin.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = OpusPlugin.xcodeproj; path = Plugins/Opus/OpusPlugin.xcodeproj; sourceTree = ""; }; 8377C66127B8CF6300E8BC0F /* SpectrumView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SpectrumView.m; path = Visualization/SpectrumView.m; sourceTree = ""; }; 8377C66227B8CF6300E8BC0F /* SpectrumView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SpectrumView.h; path = Visualization/SpectrumView.h; sourceTree = ""; }; @@ -1285,6 +1302,7 @@ 17C808830C3BD181005707C4 /* HTTPSource.xcodeproj */, 83489C4E2782F2DF00BDCEA2 /* libvgmPlayer.xcodeproj */, 8E8D40820CBB036600135C1B /* M3u.xcodeproj */, + 8372C92A27C785BD00E250C9 /* MAD.xcodeproj */, 83B0669C180D5668008E3612 /* MIDI.xcodeproj */, 17C8089E0C3BD1AB005707C4 /* Musepack.xcodeproj */, 83E5EFAC1FFEF78100659F0F /* OpenMPT.xcodeproj */, @@ -1767,6 +1785,14 @@ name = Products; sourceTree = ""; }; + 8372C92B27C785BD00E250C9 /* Products */ = { + isa = PBXGroup; + children = ( + 8372C93027C785BE00E250C9 /* MAD.bundle */, + ); + name = Products; + sourceTree = ""; + }; 8377C66027B8CF2300E8BC0F /* Visualization */ = { isa = PBXGroup; children = ( @@ -1947,6 +1973,7 @@ buildRules = ( ); dependencies = ( + 8372C93C27C7893100E250C9 /* PBXTargetDependency */, 83489C6A2782F76900BDCEA2 /* PBXTargetDependency */, 8329306F2778860C0010C07E /* PBXTargetDependency */, ED69CBC625BE32B40090B90D /* PBXTargetDependency */, @@ -2082,6 +2109,10 @@ ProductGroup = 8E8D40830CBB036600135C1B /* Products */; ProjectRef = 8E8D40820CBB036600135C1B /* M3u.xcodeproj */; }, + { + ProductGroup = 8372C92B27C785BD00E250C9 /* Products */; + ProjectRef = 8372C92A27C785BD00E250C9 /* MAD.xcodeproj */; + }, { ProductGroup = ED69CBB925BE328C0090B90D /* Products */; ProjectRef = ED69CBB825BE328C0090B90D /* MASShortcut.xcodeproj */; @@ -2305,6 +2336,13 @@ remoteRef = 836FB5461820538800B3AD2D /* PBXContainerItemProxy */; sourceTree = BUILT_PRODUCTS_DIR; }; + 8372C93027C785BE00E250C9 /* MAD.bundle */ = { + isa = PBXReferenceProxy; + fileType = wrapper.cfbundle; + path = MAD.bundle; + remoteRef = 8372C92F27C785BE00E250C9 /* PBXContainerItemProxy */; + sourceTree = BUILT_PRODUCTS_DIR; + }; 83B066A1180D5669008E3612 /* MIDI.bundle */ = { isa = PBXReferenceProxy; fileType = wrapper.cfbundle; @@ -2676,6 +2714,11 @@ name = Hively; targetProxy = 836FB5A518206F1500B3AD2D /* PBXContainerItemProxy */; }; + 8372C93C27C7893100E250C9 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + name = MAD; + targetProxy = 8372C93B27C7893100E250C9 /* PBXContainerItemProxy */; + }; 8375B36217FFEF010092A79F /* PBXTargetDependency */ = { isa = PBXTargetDependency; name = ArchiveSource; diff --git a/Plugins/MAD/MAD.xcodeproj/project.pbxproj b/Plugins/MAD/MAD.xcodeproj/project.pbxproj new file mode 100644 index 000000000..df03fac4a --- /dev/null +++ b/Plugins/MAD/MAD.xcodeproj/project.pbxproj @@ -0,0 +1,342 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 55; + objects = { + +/* Begin PBXBuildFile section */ + 8372C93527C7861300E250C9 /* MADDecoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 8372C93427C7861300E250C9 /* MADDecoder.m */; }; + 8372C93727C7863700E250C9 /* libmad.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8372C93627C7863700E250C9 /* libmad.a */; }; + 8372C93F27C7904800E250C9 /* libid3tag.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8372C93E27C7904800E250C9 /* libid3tag.a */; }; + 8372C94227C7959000E250C9 /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 8372C94127C7959000E250C9 /* libz.tbd */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 8372C92327C785BD00E250C9 /* MAD.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MAD.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; + 8372C93327C7861300E250C9 /* MADDecoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MADDecoder.h; sourceTree = ""; }; + 8372C93427C7861300E250C9 /* MADDecoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MADDecoder.m; sourceTree = ""; }; + 8372C93627C7863700E250C9 /* libmad.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libmad.a; path = ../../ThirdParty/libmad/lib/libmad.a; sourceTree = ""; }; + 8372C93827C7865A00E250C9 /* Plugin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Plugin.h; path = ../../Audio/Plugin.h; sourceTree = ""; }; + 8372C93927C7866B00E250C9 /* Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Logging.h; path = ../../Utils/Logging.h; sourceTree = ""; }; + 8372C93A27C786DD00E250C9 /* HTTPSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HTTPSource.h; path = ../HTTPSource/HTTPSource.h; sourceTree = ""; }; + 8372C93E27C7904800E250C9 /* libid3tag.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libid3tag.a; path = ../../ThirdParty/libid3tag/lib/libid3tag.a; sourceTree = ""; }; + 8372C94127C7959000E250C9 /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = usr/lib/libz.tbd; sourceTree = SDKROOT; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 8372C92027C785BD00E250C9 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 8372C94227C7959000E250C9 /* libz.tbd in Frameworks */, + 8372C93727C7863700E250C9 /* libmad.a in Frameworks */, + 8372C93F27C7904800E250C9 /* libid3tag.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 8372C91A27C785BD00E250C9 = { + isa = PBXGroup; + children = ( + 8372C93A27C786DD00E250C9 /* HTTPSource.h */, + 8372C93927C7866B00E250C9 /* Logging.h */, + 8372C93827C7865A00E250C9 /* Plugin.h */, + 8372C93327C7861300E250C9 /* MADDecoder.h */, + 8372C93427C7861300E250C9 /* MADDecoder.m */, + 8372C93E27C7904800E250C9 /* libid3tag.a */, + 8372C93627C7863700E250C9 /* libmad.a */, + 8372C92427C785BD00E250C9 /* Products */, + 8372C94027C7959000E250C9 /* Frameworks */, + ); + sourceTree = ""; + }; + 8372C92427C785BD00E250C9 /* Products */ = { + isa = PBXGroup; + children = ( + 8372C92327C785BD00E250C9 /* MAD.bundle */, + ); + name = Products; + sourceTree = ""; + }; + 8372C94027C7959000E250C9 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 8372C94127C7959000E250C9 /* libz.tbd */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 8372C92227C785BD00E250C9 /* MAD */ = { + isa = PBXNativeTarget; + buildConfigurationList = 8372C92727C785BD00E250C9 /* Build configuration list for PBXNativeTarget "MAD" */; + buildPhases = ( + 8372C91F27C785BD00E250C9 /* Sources */, + 8372C92027C785BD00E250C9 /* Frameworks */, + 8372C92127C785BD00E250C9 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = MAD; + productName = MAD; + productReference = 8372C92327C785BD00E250C9 /* MAD.bundle */; + productType = "com.apple.product-type.bundle"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 8372C91B27C785BD00E250C9 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastUpgradeCheck = 1320; + TargetAttributes = { + 8372C92227C785BD00E250C9 = { + CreatedOnToolsVersion = 13.2.1; + }; + }; + }; + buildConfigurationList = 8372C91E27C785BD00E250C9 /* Build configuration list for PBXProject "MAD" */; + compatibilityVersion = "Xcode 13.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 8372C91A27C785BD00E250C9; + productRefGroup = 8372C92427C785BD00E250C9 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 8372C92227C785BD00E250C9 /* MAD */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 8372C92127C785BD00E250C9 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 8372C91F27C785BD00E250C9 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 8372C93527C7861300E250C9 /* MADDecoder.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 8372C92527C785BD00E250C9 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 12.1; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + }; + name = Debug; + }; + 8372C92627C785BD00E250C9 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++17"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 12.1; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = macosx; + }; + name = Release; + }; + 8372C92827C785BD00E250C9 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = ""; + GENERATE_INFOPLIST_FILE = YES; + HEADER_SEARCH_PATHS = ( + ../../ThirdParty/libmad/include, + ../../ThirdParty/libid3tag/include, + ); + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INFOPLIST_KEY_NSPrincipalClass = ""; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Bundles"; + LIBRARY_SEARCH_PATHS = ( + ../../ThirdParty/libmad/lib, + ../../ThirdParty/libid3tag/lib, + ); + MACOSX_DEPLOYMENT_TARGET = 10.12; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = co.losno.MAD; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + WRAPPER_EXTENSION = bundle; + }; + name = Debug; + }; + 8372C92927C785BD00E250C9 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + CURRENT_PROJECT_VERSION = 1; + DEVELOPMENT_TEAM = ""; + GENERATE_INFOPLIST_FILE = YES; + HEADER_SEARCH_PATHS = ( + ../../ThirdParty/libmad/include, + ../../ThirdParty/libid3tag/include, + ); + INFOPLIST_KEY_NSHumanReadableCopyright = ""; + INFOPLIST_KEY_NSPrincipalClass = ""; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Bundles"; + LIBRARY_SEARCH_PATHS = ( + ../../ThirdParty/libmad/lib, + ../../ThirdParty/libid3tag/lib, + ); + MACOSX_DEPLOYMENT_TARGET = 10.12; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = co.losno.MAD; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_EMIT_LOC_STRINGS = YES; + WRAPPER_EXTENSION = bundle; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 8372C91E27C785BD00E250C9 /* Build configuration list for PBXProject "MAD" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8372C92527C785BD00E250C9 /* Debug */, + 8372C92627C785BD00E250C9 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 8372C92727C785BD00E250C9 /* Build configuration list for PBXNativeTarget "MAD" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 8372C92827C785BD00E250C9 /* Debug */, + 8372C92927C785BD00E250C9 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 8372C91B27C785BD00E250C9 /* Project object */; +} diff --git a/Plugins/MAD/MADDecoder.h b/Plugins/MAD/MADDecoder.h new file mode 100644 index 000000000..942e80086 --- /dev/null +++ b/Plugins/MAD/MADDecoder.h @@ -0,0 +1,59 @@ +// +// MADFile.h +// Cog +// +// Created by Vincent Spader on 6/17/06. +// Copyright 2006 Vincent Spader. All rights reserved. +// + +#import + +#import "MAD/mad.h" + +#import "Plugin.h" + +#define INPUT_BUFFER_SIZE 5 * 8192 + +@interface MADDecoder : NSObject { + struct mad_stream _stream; + struct mad_frame _frame; + struct mad_synth _synth; + + unsigned char _inputBuffer[INPUT_BUFFER_SIZE + MAD_BUFFER_GUARD]; + float *_outputBuffer; + long _outputFrames; + long _currentOutputFrames; + long _fileSize; + + id _source; + + BOOL _firstFrame; + + // For gapless playback of mp3s + BOOL _foundXingHeader; + BOOL _foundLAMEHeader; + BOOL _foundID3v2; + BOOL _foundiTunSMPB; + + long _framesDecoded; + uint16_t _startPadding; + uint16_t _endPadding; + + BOOL inputEOF; + + int channels; + float sampleRate; + int bitrate; + long totalFrames; + long framesToSkip; + int layer; + + NSString *genre; + NSString *album; + NSString *artist; + NSString *title; +} + +- (int)decodeMPEGFrame; + +@end diff --git a/Plugins/MAD/MADDecoder.m b/Plugins/MAD/MADDecoder.m new file mode 100644 index 000000000..fb90ab162 --- /dev/null +++ b/Plugins/MAD/MADDecoder.m @@ -0,0 +1,729 @@ +// +// MADFile.m +// Cog +// +// Created by Vincent Spader on 6/17/06. +// Copyright 2006 Vincent Spader. All rights reserved. +// + +#import "MADDecoder.h" + +#import "HTTPSource.h" + +#import "Logging.h" + +#import "id3tag.h" + +#import + +@implementation MADDecoder + +#define LAME_HEADER_SIZE ((8 * 5) + 4 + 4 + 8 + 32 + 16 + 16 + 4 + 4 + 8 + 12 + 12 + 8 + 8 + 2 + 3 + 11 + 32 + 32 + 32) + +// From vbrheadersdk: +// ======================================== +// A Xing header may be present in the ancillary +// data field of the first frame of an mp3 bitstream +// The Xing header (optionally) contains +// frames total number of audio frames in the bitstream +// bytes total number of bytes in the bitstream +// toc table of contents + +// toc (table of contents) gives seek points +// for random access +// the ith entry determines the seek point for +// i-percent duration +// seek point in bytes = (toc[i]/256.0) * total_bitstream_bytes +// e.g. half duration seek point = (toc[50]/256.0) * total_bitstream_bytes + +#define FRAMES_FLAG 0x0001 +#define BYTES_FLAG 0x0002 +#define TOC_FLAG 0x0004 +#define VBR_SCALE_FLAG 0x0008 + +// Scan file quickly +- (void)bufferRefill:(struct mad_stream *)stream { + long bytesToRead, bytesRemaining; + + if(NULL == stream->buffer || MAD_ERROR_BUFLEN == stream->error) { + if(stream->next_frame) { + bytesRemaining = stream->bufend - stream->next_frame; + + memmove(_inputBuffer, stream->next_frame, bytesRemaining); + + bytesToRead = INPUT_BUFFER_SIZE - bytesRemaining; + } else { + bytesToRead = INPUT_BUFFER_SIZE; + bytesRemaining = 0; + } + + // Read raw bytes from the MP3 file + long bytesRead = [_source read:_inputBuffer + bytesRemaining amount:bytesToRead]; + + if(bytesRead == 0) { + memset(_inputBuffer + bytesRemaining + bytesRead, 0, MAD_BUFFER_GUARD); + bytesRead += MAD_BUFFER_GUARD; + inputEOF = YES; + } + + mad_stream_buffer(stream, _inputBuffer, bytesRead + bytesRemaining); + stream->error = MAD_ERROR_NONE; + } +} + +- (BOOL)scanFile { + struct mad_stream stream; + struct mad_frame frame; + + long framesDecoded = 0; + int samplesPerMPEGFrame = 0; + + int id3_length = 0; + + mad_stream_init(&stream); + mad_frame_init(&frame); + + [_source seek:0 whence:SEEK_END]; + _fileSize = [_source tell]; + [_source seek:0 whence:SEEK_SET]; + + mad_timer_t duration = { 0, 0 }; + + for(;;) { + [self bufferRefill:&stream]; + + if(mad_frame_decode(&frame, &stream) == -1) { + if(MAD_RECOVERABLE(stream.error)) { + // Prevent ID3 tags from reporting recoverable frame errors + const uint8_t *buffer = stream.this_frame; + unsigned long buflen = stream.bufend - stream.this_frame; + + if(10 <= buflen && 0x49 == buffer[0] && 0x44 == buffer[1] && 0x33 == buffer[2]) { + id3_length = (((buffer[6] & 0x7F) << (3 * 7)) | ((buffer[7] & 0x7F) << (2 * 7)) | + ((buffer[8] & 0x7F) << (1 * 7)) | ((buffer[9] & 0x7F) << (0 * 7))); + + _foundID3v2 = YES; + + // Add 10 bytes for ID3 header + id3_length += 10; + + void *tagBuffer = malloc(id3_length); + if(!tagBuffer) return NO; + + memcpy(tagBuffer, &buffer[0], MIN(buflen, id3_length)); + + long bufleft = id3_length - buflen; + long tagRead = MIN(buflen, id3_length); + + while(bufleft > 0) { + stream.error = MAD_ERROR_BUFLEN; + stream.next_frame = NULL; + [self bufferRefill:&stream]; + buffer = stream.this_frame; + buflen = stream.bufend - stream.this_frame; + memcpy(tagBuffer + tagRead, buffer, MIN(buflen, bufleft)); + tagRead += MIN(buflen, bufleft); + bufleft -= buflen; + } + + if(bufleft < 0) { + mad_stream_skip(&stream, buflen + bufleft); + } + + struct id3_tag *tag = id3_tag_parse(tagBuffer, id3_length); + + if(tag) { + for(size_t i = 0; i < tag->nframes; ++i) { + struct id3_frame *frame = tag->frames[i]; + if(!strcmp(frame->id, "COMM")) { + union id3_field *field; + const id3_ucs4_t *description; + const id3_ucs4_t *value; + + field = id3_frame_field(frame, 2); + description = id3_field_getstring(field); + + field = id3_frame_field(frame, 3); + value = id3_field_getfullstring(field); + + if(description && value) { + id3_utf8_t *description8 = id3_ucs4_utf8duplicate(description); + if(!strcmp((const char *)description8, "iTunSMPB")) { + id3_utf8_t *value8 = id3_ucs4_utf8duplicate(value); + + uint32_t zero, start_pad, end_pad; + uint64_t last_eight_frames_offset; + int64_t temp_duration; + + if(sscanf((const char *)value8, "%" PRIx32 " %" PRIx32 " %" PRIx32 " %" PRIx64 " %" PRIx32 " %" PRIx64, &zero, &start_pad, &end_pad, &temp_duration, &zero, &last_eight_frames_offset) == 6 && + temp_duration >= 0 && + start_pad <= (576 * 2 * 32) && + end_pad <= (576 * 2 * 64) && + (_fileSize && (last_eight_frames_offset < (_fileSize - id3_length)))) { + if(end_pad >= 528 + 1) { + _startPadding = start_pad + 528 + 1; + _endPadding = end_pad - (528 + 1); + totalFrames = temp_duration; + _foundiTunSMPB = YES; + } + } + + free(value8); + } + free(description8); + } + } + } + + id3_tag_delete(tag); + } + + free(tagBuffer); + } + + continue; + } else if(stream.error == MAD_ERROR_BUFLEN && inputEOF) { + break; + } else if(stream.error == MAD_ERROR_BUFLEN) { + continue; + } else { + // DLog(@"Unrecoverable error: %s", mad_stream_errorstr(&stream)); + break; + } + } + framesDecoded++; + + if(framesDecoded == 1) { + sampleRate = frame.header.samplerate; + channels = MAD_NCHANNELS(&frame.header); + + if(MAD_FLAG_LSF_EXT & frame.header.flags || MAD_FLAG_MPEG_2_5_EXT & frame.header.flags) { + switch(frame.header.layer) { + case MAD_LAYER_I: + samplesPerMPEGFrame = 384; + layer = 1; + break; + case MAD_LAYER_II: + samplesPerMPEGFrame = 1152; + layer = 2; + break; + case MAD_LAYER_III: + samplesPerMPEGFrame = 576; + layer = 3; + break; + } + } else { + switch(frame.header.layer) { + case MAD_LAYER_I: + samplesPerMPEGFrame = 384; + layer = 1; + break; + case MAD_LAYER_II: + samplesPerMPEGFrame = 1152; + layer = 2; + break; + case MAD_LAYER_III: + samplesPerMPEGFrame = 1152; + layer = 3; + break; + } + } + + unsigned ancillaryBitsRemaining = stream.anc_bitlen; + + if(32 > ancillaryBitsRemaining) + continue; + + uint32_t magic = (uint32_t)mad_bit_read(&stream.anc_ptr, 32); + ancillaryBitsRemaining -= 32; + + if('Xing' == magic || 'Info' == magic) { + unsigned i; + uint32_t flags = 0, frames = 0, bytes = 0, vbrScale = 0; + + if(32 > ancillaryBitsRemaining) + continue; + + flags = (uint32_t)mad_bit_read(&stream.anc_ptr, 32); + ancillaryBitsRemaining -= 32; + + // 4 byte value containing total frames + if(FRAMES_FLAG & flags) { + if(32 > ancillaryBitsRemaining) + continue; + + frames = (uint32_t)mad_bit_read(&stream.anc_ptr, 32); + ancillaryBitsRemaining -= 32; + + // Determine number of samples, discounting encoder delay and padding + // Our concept of a frame is the same as CoreAudio's- one sample across all channels + totalFrames = frames * samplesPerMPEGFrame; + // DLog(@"TOTAL READ FROM XING"); + } + + // 4 byte value containing total bytes + if(BYTES_FLAG & flags) { + if(32 > ancillaryBitsRemaining) + continue; + + bytes = (uint32_t)mad_bit_read(&stream.anc_ptr, 32); + ancillaryBitsRemaining -= 32; + } + + // 100 bytes containing TOC information + if(TOC_FLAG & flags) { + if(8 * 100 > ancillaryBitsRemaining) + continue; + + for(i = 0; i < 100; ++i) + /*_xingTOC[i] = */ mad_bit_read(&stream.anc_ptr, 8); + + ancillaryBitsRemaining -= (8 * 100); + } + + // 4 byte value indicating encoded vbr scale + if(VBR_SCALE_FLAG & flags) { + if(32 > ancillaryBitsRemaining) + continue; + + vbrScale = (uint32_t)mad_bit_read(&stream.anc_ptr, 32); + ancillaryBitsRemaining -= 32; + } + + framesDecoded = frames; + + _foundXingHeader = YES; + + // Loook for the LAME header next + // http://gabriel.mp3-tech.org/mp3infotag.html + if(32 > ancillaryBitsRemaining) + continue; + magic = (uint32_t)mad_bit_read(&stream.anc_ptr, 32); + + ancillaryBitsRemaining -= 32; + + if('LAME' == magic) { + if(LAME_HEADER_SIZE > ancillaryBitsRemaining) + continue; + + /*unsigned char versionString [5 + 1]; + memset(versionString, 0, 6);*/ + + for(i = 0; i < 5; ++i) + /*versionString[i] =*/mad_bit_read(&stream.anc_ptr, 8); + + /*uint8_t infoTagRevision =*/mad_bit_read(&stream.anc_ptr, 4); + /*uint8_t vbrMethod =*/mad_bit_read(&stream.anc_ptr, 4); + + /*uint8_t lowpassFilterValue =*/mad_bit_read(&stream.anc_ptr, 8); + + /*float peakSignalAmplitude =*/mad_bit_read(&stream.anc_ptr, 32); + /*uint16_t radioReplayGain =*/mad_bit_read(&stream.anc_ptr, 16); + /*uint16_t audiophileReplayGain =*/mad_bit_read(&stream.anc_ptr, 16); + + /*uint8_t encodingFlags =*/mad_bit_read(&stream.anc_ptr, 4); + /*uint8_t athType =*/mad_bit_read(&stream.anc_ptr, 4); + + /*uint8_t lameBitrate =*/mad_bit_read(&stream.anc_ptr, 8); + + _startPadding = mad_bit_read(&stream.anc_ptr, 12); + _endPadding = mad_bit_read(&stream.anc_ptr, 12); + + _startPadding += 528 + 1; // MDCT/filterbank delay + _endPadding -= 528 + 1; + + /*uint8_t misc =*/mad_bit_read(&stream.anc_ptr, 8); + + uint8_t mp3Gain = mad_bit_read(&stream.anc_ptr, 8); + DLog(@"Gain: %i", mp3Gain); + + /*uint8_t unused =*/mad_bit_read(&stream.anc_ptr, 2); + /*uint8_t surroundInfo =*/mad_bit_read(&stream.anc_ptr, 3); + /*uint16_t presetInfo =*/mad_bit_read(&stream.anc_ptr, 11); + + /*uint32_t musicGain =*/mad_bit_read(&stream.anc_ptr, 32); + + /*uint32_t musicCRC =*/mad_bit_read(&stream.anc_ptr, 32); + + /*uint32_t tagCRC =*/mad_bit_read(&stream.anc_ptr, 32); + + ancillaryBitsRemaining -= LAME_HEADER_SIZE; + + _foundLAMEHeader = YES; + break; + } + } + } else if(_foundiTunSMPB) { + break; + } + + mad_timer_add(&duration, frame.header.duration); + } + + if(!_foundiTunSMPB && (!_foundXingHeader || !_foundLAMEHeader)) { + totalFrames = mad_timer_count(duration, sampleRate); + } + + bitrate = ((double)((_fileSize - id3_length) * 8) / 1000.0) * (sampleRate / (double)totalFrames); + + mad_frame_finish(&frame); + mad_stream_finish(&stream); + + [_source seek:0 whence:SEEK_SET]; + inputEOF = NO; + + DLog(@"Mad properties: %@", [self properties]); + + return YES; +} + +- (BOOL)open:(id)source { + _source = source; + + /* First the structures used by libmad must be initialized. */ + mad_stream_init(&_stream); + mad_frame_init(&_frame); + mad_synth_init(&_synth); + + _firstFrame = YES; + // DLog(@"OPEN: %i", _firstFrame); + + inputEOF = NO; + + genre = @""; + album = @""; + artist = @""; + title = @""; + + if(![_source seekable]) { + // Decode the first frame to get the channels, samplerate, etc. + int r; + do { + r = [self decodeMPEGFrame]; + DLog(@"Decoding first frame: %i", r); + } while(r == 0); + + return (r == -1 ? NO : YES); + } + + framesToSkip = 0; + + BOOL ret = [self scanFile]; + + if(_foundLAMEHeader || _foundiTunSMPB) { + framesToSkip = _startPadding; + } + + return ret; +} + +- (void)writeOutput { + unsigned long startingSample = 0; + unsigned long sampleCount = _synth.pcm.length; + + // DLog(@"Position: %li/%li", _framesDecoded, totalFrames); + // DLog(@"<%i, %i>", _startPadding, _endPadding); + if(framesToSkip > 0) { + startingSample = framesToSkip; + } + + // DLog(@"Counts: %i, %i", startingSample, sampleCount); + if(_foundLAMEHeader || _foundiTunSMPB) { + // Past the end of the file. + if(totalFrames - _endPadding <= _framesDecoded) { + // DLog(@"End of file. Not writing."); + return; + } + + // We are at the end of the file and need to read the last few frames + if(_framesDecoded + (sampleCount - startingSample) > totalFrames - _endPadding) { + // DLog(@"End of file. %li", totalFrames - _endPadding - _framesDecoded); + sampleCount = totalFrames - _endPadding - _framesDecoded + startingSample; + } + } + + // We haven't even gotten to the start yet + if(startingSample >= sampleCount) { + // DLog(@"Skipping entire sample"); + _framesDecoded += sampleCount; + framesToSkip -= sampleCount; + return; + } + + framesToSkip = 0; + + // DLog(@"Revised: %i, %i", startingSample, sampleCount); + + _framesDecoded += _synth.pcm.length; + + if(_outputFrames > 0) { + DLog(@"LOSING FRAMES!"); + } + _outputFrames = (sampleCount - startingSample); + + if(_currentOutputFrames < _outputFrames) { + _outputBuffer = (float *)realloc(_outputBuffer, _outputFrames * channels * sizeof(float)); + _currentOutputFrames = _outputFrames; + } + + int ch; + + // samples [0 ... n] + float scale = (float)MAD_F_ONE; + for(ch = 0; ch < channels; ch++) { + vDSP_vflt32(&_synth.pcm.samples[ch][startingSample], 1, &_outputBuffer[ch], channels, _outputFrames); + vDSP_vsdiv(&_outputBuffer[ch], channels, &scale, &_outputBuffer[ch], channels, _outputFrames); + } + + // Output to a file + // FILE *f = fopen("data.raw", "a"); + // fwrite(_outputBuffer, channels * 2, _outputFrames, f); + // fclose(f); +} + +- (int)decodeMPEGFrame { + if(_stream.buffer == NULL || _stream.error == MAD_ERROR_BUFLEN) { + int inputToRead; + int inputRemaining; + + if(_stream.next_frame != NULL) { + inputRemaining = (int)(_stream.bufend - _stream.next_frame); + + memmove(_inputBuffer, _stream.next_frame, inputRemaining); + + inputToRead = INPUT_BUFFER_SIZE - inputRemaining; + } else { + inputToRead = INPUT_BUFFER_SIZE; + inputRemaining = 0; + } + + long inputRead = [_source read:_inputBuffer + inputRemaining amount:INPUT_BUFFER_SIZE - inputRemaining]; + if(inputRead == 0) { + memset(_inputBuffer + inputRemaining + inputRead, 0, MAD_BUFFER_GUARD); + inputRead += MAD_BUFFER_GUARD; + inputEOF = YES; + } + + mad_stream_buffer(&_stream, _inputBuffer, inputRead + inputRemaining); + _stream.error = MAD_ERROR_NONE; + // DLog(@"Read stream."); + } + + if(mad_frame_decode(&_frame, &_stream) == -1) { + if(MAD_RECOVERABLE(_stream.error)) { + const uint8_t *buffer = _stream.this_frame; + unsigned long buflen = _stream.bufend - _stream.this_frame; + uint32_t id3_length = 0; + + // No longer need ID3Tag framework + if(10 <= buflen && 0x49 == buffer[0] && 0x44 == buffer[1] && 0x33 == buffer[2]) { + id3_length = (((buffer[6] & 0x7F) << (3 * 7)) | ((buffer[7] & 0x7F) << (2 * 7)) | + ((buffer[8] & 0x7F) << (1 * 7)) | ((buffer[9] & 0x7F) << (0 * 7))); + + // Add 10 bytes for ID3 header + id3_length += 10; + + mad_stream_skip(&_stream, id3_length); + } + + DLog(@"recoverable error"); + return 0; + } else if(MAD_ERROR_BUFLEN == _stream.error && inputEOF) { + DLog(@"EOF"); + return -1; + } else if(MAD_ERROR_BUFLEN == _stream.error) { + // DLog(@"Bufferlen"); + return 0; + } else { + // DLog(@"Unrecoverable stream error: %s", mad_stream_errorstr(&_stream)); + return -1; + } + } + + signed long frameDuration = mad_timer_count(_frame.header.duration, sampleRate); + if((framesToSkip - 1152 * 4) >= frameDuration) { + framesToSkip -= frameDuration; + _framesDecoded += frameDuration; + return 0; + } + + // DLog(@"Decoded buffer."); + mad_synth_frame(&_synth, &_frame); + // DLog(@"first frame: %i", _firstFrame); + if(_firstFrame) { + _firstFrame = NO; + + if(![_source seekable]) { + sampleRate = _frame.header.samplerate; + channels = MAD_NCHANNELS(&_frame.header); + + switch(_frame.header.layer) { + case MAD_LAYER_I: + layer = 1; + break; + case MAD_LAYER_II: + layer = 2; + break; + case MAD_LAYER_III: + layer = 3; + break; + default: + break; + } + + [self willChangeValueForKey:@"properties"]; + [self didChangeValueForKey:@"properties"]; + } + // DLog(@"FIRST FRAME!!! %i %i", _foundXingHeader, _foundLAMEHeader); + if(_foundXingHeader) { + // DLog(@"Skipping xing header."); + return 0; + } + } + + return 1; +} + +- (int)readAudio:(void *)buffer frames:(UInt32)frames { + int framesRead = 0; + + for(;;) { + long framesRemaining = frames - framesRead; + long framesToCopy = (_outputFrames > framesRemaining ? framesRemaining : _outputFrames); + + if(framesToCopy) { + memcpy(buffer + (framesRead * channels * sizeof(float)), _outputBuffer, framesToCopy * channels * sizeof(float)); + framesRead += framesToCopy; + + if(framesToCopy != _outputFrames) { + memmove(_outputBuffer, _outputBuffer + (framesToCopy * channels), (_outputFrames - framesToCopy) * channels * sizeof(float)); + } + + _outputFrames -= framesToCopy; + } + + if(framesRead == frames) + break; + + int r = [self decodeMPEGFrame]; + // DLog(@"Decoding frame: %i", r); + if(r == 0) // Recoverable error. + continue; + else if(r == -1) // Unrecoverable error + break; + + [self writeOutput]; + // DLog(@"Wrote output"); + } + + [self updateMetadata]; + + // DLog(@"Read: %i/%i", bytesRead, size); + return framesRead; +} + +- (void)close { + if(_source) { + [_source close]; + _source = nil; + } + + if(_outputBuffer) { + free(_outputBuffer); + _outputBuffer = NULL; + } + + mad_synth_finish(&_synth); + mad_frame_finish(&_frame); + mad_stream_finish(&_stream); +} + +- (long)seek:(long)frame { + if(frame > totalFrames) + frame = totalFrames; + + framesToSkip = 0; + + if(frame > _framesDecoded) { + _framesDecoded = 0; + _firstFrame = YES; + if(_foundLAMEHeader || _foundiTunSMPB) + framesToSkip = _startPadding; + [_source seek:0 whence:SEEK_SET]; + + mad_stream_buffer(&_stream, NULL, 0); + } + + framesToSkip += frame - _framesDecoded; + + return frame; +} + +- (void)updateMetadata { + NSString *_artist = artist; + NSString *_album = album; + NSString *_title = title; + NSString *_genre = genre; + + Class sourceClass = [_source class]; + if([sourceClass isEqual:NSClassFromString(@"HTTPSource")]) { + HTTPSource *httpSource = (HTTPSource *)_source; + if([httpSource hasMetadata]) { + NSDictionary *metadata = [httpSource metadata]; + _genre = [metadata valueForKey:@"genre"]; + _album = [metadata valueForKey:@"album"]; + _artist = [metadata valueForKey:@"artist"]; + _title = [metadata valueForKey:@"title"]; + } + } + + if(![_artist isEqual:artist] || + ![_album isEqual:album] || + ![_title isEqual:title] || + ![_genre isEqual:genre]) { + artist = _artist; + album = _album; + title = _title; + genre = _genre; + if(![_source seekable]) { + [self willChangeValueForKey:@"metadata"]; + [self didChangeValueForKey:@"metadata"]; + } + } +} + +- (NSDictionary *)properties { + const NSString *layers[3] = { @"MP1", @"MP2", @"MP3" }; + return @{ @"channels": [NSNumber numberWithInt:channels], + @"bitsPerSample": [NSNumber numberWithInt:32], + @"sampleRate": [NSNumber numberWithFloat:sampleRate], + @"floatingPoint": [NSNumber numberWithBool:YES], + @"bitrate": [NSNumber numberWithInt:bitrate], + @"totalFrames": [NSNumber numberWithLong:totalFrames - (_startPadding + _endPadding)], + @"seekable": [NSNumber numberWithBool:[_source seekable]], + @"codec": layers[layer - 1], + @"endian": @"host", + @"encoding": @"lossy" }; +} + +- (NSDictionary *)metadata { + return @{ @"artist": artist, @"album": album, @"title": title, @"genre": genre }; +} + ++ (NSArray *)fileTypes { + return @[@"mp3", @"m2a", @"mpa"]; +} + ++ (NSArray *)mimeTypes { + return @[@"audio/mpeg", @"audio/x-mp3"]; +} + ++ (NSArray *)fileTypeAssociations { + return @[@[@"MPEG Audio File", @"mp3.icns", @"mp3", @"m2a", @"mpa"]]; +} + ++ (float)priority { + return 2.0; +} + +@end diff --git a/ThirdParty/libid3tag/README.md b/ThirdParty/libid3tag/README.md new file mode 100644 index 000000000..a983836af --- /dev/null +++ b/ThirdParty/libid3tag/README.md @@ -0,0 +1,21 @@ +Built with the Arch Linux defaults, sort of: + +``` +patch -Np1 -i 10_utf16.diff +patch -Np1 -i 11_unknown_encoding.diff +patch -Np0 -i CVE-2008-2109.patch +patch -Np1 -i libid3tag-gperf.patch +rm compat.c frametype.c + +touch NEWS +touch AUTHORS +touch ChangeLog + +autoreconf -fiv +./configure +make -j8 CFLAGS="-Os -arch x86_64 -arch arm64 -mmacosx-version-min=10.12" LDFLAGS="-arch x86_64 -arch arm64 -mmacosx-version-min=10.12" +``` + +Version 0.15.1b was used, with Arch Linux patches. I also had to tweak +the compat.c and frametype.c to change the function definitions to match +the gperf patch used above. diff --git a/ThirdParty/libid3tag/include/id3tag.h b/ThirdParty/libid3tag/include/id3tag.h new file mode 100644 index 000000000..4f4c6819a --- /dev/null +++ b/ThirdParty/libid3tag/include/id3tag.h @@ -0,0 +1,364 @@ +/* + * libid3tag - ID3 tag manipulation library + * Copyright (C) 2000-2004 Underbit Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * If you would like to negotiate alternate licensing terms, you may do + * so by contacting: Underbit Technologies, Inc. + * + * $Id: id3tag.h,v 1.17 2004/01/23 23:22:46 rob Exp $ + */ + +# ifndef LIBID3TAG_ID3TAG_H +# define LIBID3TAG_ID3TAG_H + +# ifdef __cplusplus +extern "C" { +# endif + +# define ID3_TAG_VERSION 0x0400 +# define ID3_TAG_VERSION_MAJOR(x) (((x) >> 8) & 0xff) +# define ID3_TAG_VERSION_MINOR(x) (((x) >> 0) & 0xff) + +typedef unsigned char id3_byte_t; +typedef unsigned long id3_length_t; + +typedef unsigned long id3_ucs4_t; + +typedef unsigned char id3_latin1_t; +typedef unsigned short id3_utf16_t; +typedef signed char id3_utf8_t; + +struct id3_tag { + unsigned int refcount; + unsigned int version; + int flags; + int extendedflags; + int restrictions; + int options; + unsigned int nframes; + struct id3_frame **frames; + id3_length_t paddedsize; +}; + +# define ID3_TAG_QUERYSIZE 10 + +/* ID3v1 field frames */ + +# define ID3_FRAME_TITLE "TIT2" +# define ID3_FRAME_ARTIST "TPE1" +# define ID3_FRAME_ALBUM "TALB" +# define ID3_FRAME_TRACK "TRCK" +# define ID3_FRAME_YEAR "TDRC" +# define ID3_FRAME_GENRE "TCON" +# define ID3_FRAME_COMMENT "COMM" + +/* special frames */ + +# define ID3_FRAME_OBSOLETE "ZOBS" /* with apologies to the French */ + +/* tag flags */ + +enum { + ID3_TAG_FLAG_UNSYNCHRONISATION = 0x80, + ID3_TAG_FLAG_EXTENDEDHEADER = 0x40, + ID3_TAG_FLAG_EXPERIMENTALINDICATOR = 0x20, + ID3_TAG_FLAG_FOOTERPRESENT = 0x10, + + ID3_TAG_FLAG_KNOWNFLAGS = 0xf0 +}; + +/* tag extended flags */ + +enum { + ID3_TAG_EXTENDEDFLAG_TAGISANUPDATE = 0x40, + ID3_TAG_EXTENDEDFLAG_CRCDATAPRESENT = 0x20, + ID3_TAG_EXTENDEDFLAG_TAGRESTRICTIONS = 0x10, + + ID3_TAG_EXTENDEDFLAG_KNOWNFLAGS = 0x70 +}; + +/* tag restrictions */ + +enum { + ID3_TAG_RESTRICTION_TAGSIZE_MASK = 0xc0, + ID3_TAG_RESTRICTION_TAGSIZE_128_FRAMES_1_MB = 0x00, + ID3_TAG_RESTRICTION_TAGSIZE_64_FRAMES_128_KB = 0x40, + ID3_TAG_RESTRICTION_TAGSIZE_32_FRAMES_40_KB = 0x80, + ID3_TAG_RESTRICTION_TAGSIZE_32_FRAMES_4_KB = 0xc0 +}; + +enum { + ID3_TAG_RESTRICTION_TEXTENCODING_MASK = 0x20, + ID3_TAG_RESTRICTION_TEXTENCODING_NONE = 0x00, + ID3_TAG_RESTRICTION_TEXTENCODING_LATIN1_UTF8 = 0x20 +}; + +enum { + ID3_TAG_RESTRICTION_TEXTSIZE_MASK = 0x18, + ID3_TAG_RESTRICTION_TEXTSIZE_NONE = 0x00, + ID3_TAG_RESTRICTION_TEXTSIZE_1024_CHARS = 0x08, + ID3_TAG_RESTRICTION_TEXTSIZE_128_CHARS = 0x10, + ID3_TAG_RESTRICTION_TEXTSIZE_30_CHARS = 0x18 +}; + +enum { + ID3_TAG_RESTRICTION_IMAGEENCODING_MASK = 0x04, + ID3_TAG_RESTRICTION_IMAGEENCODING_NONE = 0x00, + ID3_TAG_RESTRICTION_IMAGEENCODING_PNG_JPEG = 0x04 +}; + +enum { + ID3_TAG_RESTRICTION_IMAGESIZE_MASK = 0x03, + ID3_TAG_RESTRICTION_IMAGESIZE_NONE = 0x00, + ID3_TAG_RESTRICTION_IMAGESIZE_256_256 = 0x01, + ID3_TAG_RESTRICTION_IMAGESIZE_64_64 = 0x02, + ID3_TAG_RESTRICTION_IMAGESIZE_64_64_EXACT = 0x03 +}; + +/* library options */ + +enum { + ID3_TAG_OPTION_UNSYNCHRONISATION = 0x0001, /* use unsynchronisation */ + ID3_TAG_OPTION_COMPRESSION = 0x0002, /* use compression */ + ID3_TAG_OPTION_CRC = 0x0004, /* use CRC */ + + ID3_TAG_OPTION_APPENDEDTAG = 0x0010, /* tag will be appended */ + ID3_TAG_OPTION_FILEALTERED = 0x0020, /* audio data was altered */ + + ID3_TAG_OPTION_ID3V1 = 0x0100 /* render ID3v1/ID3v1.1 tag */ +}; + +struct id3_frame { + char id[5]; + char const *description; + unsigned int refcount; + int flags; + int group_id; + int encryption_method; + id3_byte_t *encoded; + id3_length_t encoded_length; + id3_length_t decoded_length; + unsigned int nfields; + union id3_field *fields; +}; + +enum { + /* frame status flags */ + ID3_FRAME_FLAG_TAGALTERPRESERVATION = 0x4000, + ID3_FRAME_FLAG_FILEALTERPRESERVATION = 0x2000, + ID3_FRAME_FLAG_READONLY = 0x1000, + + ID3_FRAME_FLAG_STATUSFLAGS = 0xff00, + + /* frame format flags */ + ID3_FRAME_FLAG_GROUPINGIDENTITY = 0x0040, + ID3_FRAME_FLAG_COMPRESSION = 0x0008, + ID3_FRAME_FLAG_ENCRYPTION = 0x0004, + ID3_FRAME_FLAG_UNSYNCHRONISATION = 0x0002, + ID3_FRAME_FLAG_DATALENGTHINDICATOR = 0x0001, + + ID3_FRAME_FLAG_FORMATFLAGS = 0x00ff, + + ID3_FRAME_FLAG_KNOWNFLAGS = 0x704f +}; + +enum id3_field_type { + ID3_FIELD_TYPE_TEXTENCODING, + ID3_FIELD_TYPE_LATIN1, + ID3_FIELD_TYPE_LATIN1FULL, + ID3_FIELD_TYPE_LATIN1LIST, + ID3_FIELD_TYPE_STRING, + ID3_FIELD_TYPE_STRINGFULL, + ID3_FIELD_TYPE_STRINGLIST, + ID3_FIELD_TYPE_LANGUAGE, + ID3_FIELD_TYPE_FRAMEID, + ID3_FIELD_TYPE_DATE, + ID3_FIELD_TYPE_INT8, + ID3_FIELD_TYPE_INT16, + ID3_FIELD_TYPE_INT24, + ID3_FIELD_TYPE_INT32, + ID3_FIELD_TYPE_INT32PLUS, + ID3_FIELD_TYPE_BINARYDATA +}; + +enum id3_field_textencoding { + ID3_FIELD_TEXTENCODING_ISO_8859_1 = 0x00, + ID3_FIELD_TEXTENCODING_UTF_16 = 0x01, + ID3_FIELD_TEXTENCODING_UTF_16BE = 0x02, + ID3_FIELD_TEXTENCODING_UTF_8 = 0x03 +}; + +union id3_field { + enum id3_field_type type; + struct { + enum id3_field_type type; + signed long value; + } number; + struct { + enum id3_field_type type; + id3_latin1_t *ptr; + } latin1; + struct { + enum id3_field_type type; + unsigned int nstrings; + id3_latin1_t **strings; + } latin1list; + struct { + enum id3_field_type type; + id3_ucs4_t *ptr; + } string; + struct { + enum id3_field_type type; + unsigned int nstrings; + id3_ucs4_t **strings; + } stringlist; + struct { + enum id3_field_type type; + char value[9]; + } immediate; + struct { + enum id3_field_type type; + id3_byte_t *data; + id3_length_t length; + } binary; +}; + +/* file interface */ + +enum id3_file_mode { + ID3_FILE_MODE_READONLY = 0, + ID3_FILE_MODE_READWRITE +}; + +struct id3_file *id3_file_open(char const *, enum id3_file_mode); +struct id3_file *id3_file_fdopen(int, enum id3_file_mode); +int id3_file_close(struct id3_file *); + +struct id3_tag *id3_file_tag(struct id3_file const *); + +int id3_file_update(struct id3_file *); + +/* tag interface */ + +struct id3_tag *id3_tag_new(void); +void id3_tag_delete(struct id3_tag *); + +unsigned int id3_tag_version(struct id3_tag const *); + +int id3_tag_options(struct id3_tag *, int, int); +void id3_tag_setlength(struct id3_tag *, id3_length_t); + +void id3_tag_clearframes(struct id3_tag *); + +int id3_tag_attachframe(struct id3_tag *, struct id3_frame *); +int id3_tag_detachframe(struct id3_tag *, struct id3_frame *); + +struct id3_frame *id3_tag_findframe(struct id3_tag const *, + char const *, unsigned int); + +signed long id3_tag_query(id3_byte_t const *, id3_length_t); + +struct id3_tag *id3_tag_parse(id3_byte_t const *, id3_length_t); +id3_length_t id3_tag_render(struct id3_tag const *, id3_byte_t *); + +/* frame interface */ + +struct id3_frame *id3_frame_new(char const *); +void id3_frame_delete(struct id3_frame *); + +union id3_field *id3_frame_field(struct id3_frame const *, unsigned int); + +/* field interface */ + +enum id3_field_type id3_field_type(union id3_field const *); + +int id3_field_setint(union id3_field *, signed long); +int id3_field_settextencoding(union id3_field *, enum id3_field_textencoding); +int id3_field_setstrings(union id3_field *, unsigned int, id3_ucs4_t **); +int id3_field_addstring(union id3_field *, id3_ucs4_t const *); +int id3_field_setlanguage(union id3_field *, char const *); +int id3_field_setlatin1(union id3_field *, id3_latin1_t const *); +int id3_field_setfulllatin1(union id3_field *, id3_latin1_t const *); +int id3_field_setstring(union id3_field *, id3_ucs4_t const *); +int id3_field_setfullstring(union id3_field *, id3_ucs4_t const *); +int id3_field_setframeid(union id3_field *, char const *); +int id3_field_setbinarydata(union id3_field *, + id3_byte_t const *, id3_length_t); + +signed long id3_field_getint(union id3_field const *); +enum id3_field_textencoding id3_field_gettextencoding(union id3_field const *); +id3_latin1_t const *id3_field_getlatin1(union id3_field const *); +id3_latin1_t const *id3_field_getfulllatin1(union id3_field const *); +id3_ucs4_t const *id3_field_getstring(union id3_field const *); +id3_ucs4_t const *id3_field_getfullstring(union id3_field const *); +unsigned int id3_field_getnstrings(union id3_field const *); +id3_ucs4_t const *id3_field_getstrings(union id3_field const *, + unsigned int); +char const *id3_field_getframeid(union id3_field const *); +id3_byte_t const *id3_field_getbinarydata(union id3_field const *, + id3_length_t *); + +/* genre interface */ + +id3_ucs4_t const *id3_genre_index(unsigned int); +id3_ucs4_t const *id3_genre_name(id3_ucs4_t const *); +int id3_genre_number(id3_ucs4_t const *); + +/* ucs4 interface */ + +id3_latin1_t *id3_ucs4_latin1duplicate(id3_ucs4_t const *); +id3_utf16_t *id3_ucs4_utf16duplicate(id3_ucs4_t const *); +id3_utf8_t *id3_ucs4_utf8duplicate(id3_ucs4_t const *); + +void id3_ucs4_putnumber(id3_ucs4_t *, unsigned long); +unsigned long id3_ucs4_getnumber(id3_ucs4_t const *); + +/* latin1/utf16/utf8 interfaces */ + +id3_ucs4_t *id3_latin1_ucs4duplicate(id3_latin1_t const *); +id3_ucs4_t *id3_utf16_ucs4duplicate(id3_utf16_t const *); +id3_ucs4_t *id3_utf8_ucs4duplicate(id3_utf8_t const *); + +/* version interface */ + +# define ID3_VERSION_MAJOR 0 +# define ID3_VERSION_MINOR 15 +# define ID3_VERSION_PATCH 1 +# define ID3_VERSION_EXTRA " (beta)" + +# define ID3_VERSION_STRINGIZE(str) #str +# define ID3_VERSION_STRING(num) ID3_VERSION_STRINGIZE(num) + +# define ID3_VERSION ID3_VERSION_STRING(ID3_VERSION_MAJOR) "." \ + ID3_VERSION_STRING(ID3_VERSION_MINOR) "." \ + ID3_VERSION_STRING(ID3_VERSION_PATCH) \ + ID3_VERSION_EXTRA + +# define ID3_PUBLISHYEAR "2000-2004" +# define ID3_AUTHOR "Underbit Technologies, Inc." +# define ID3_EMAIL "info@underbit.com" + +extern char const id3_version[]; +extern char const id3_copyright[]; +extern char const id3_author[]; +extern char const id3_build[]; + +# ifdef __cplusplus +} +# endif + +# endif diff --git a/ThirdParty/libid3tag/lib/libid3tag.a b/ThirdParty/libid3tag/lib/libid3tag.a new file mode 100644 index 000000000..040ae74dd Binary files /dev/null and b/ThirdParty/libid3tag/lib/libid3tag.a differ diff --git a/ThirdParty/libid3tag/patches/10_utf16.diff b/ThirdParty/libid3tag/patches/10_utf16.diff new file mode 100644 index 000000000..a3218d26d --- /dev/null +++ b/ThirdParty/libid3tag/patches/10_utf16.diff @@ -0,0 +1,48 @@ +#! /bin/sh -e +## 10_utf16.dpatch by +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: Handle bogus UTF16 sequences that have a length that is not +## DP: an even number of 8 bit characters. + +if [ $# -lt 1 ]; then + echo "`basename $0`: script expects -patch|-unpatch as argument" >&2 + exit 1 +fi + +[ -f debian/patches/00patch-opts ] && . debian/patches/00patch-opts +patch_opts="${patch_opts:--f --no-backup-if-mismatch} ${2:+-d $2}" + +case "$1" in + -patch) patch -p1 ${patch_opts} < $0;; + -unpatch) patch -R -p1 ${patch_opts} < $0;; + *) + echo "`basename $0`: script expects -patch|-unpatch as argument" >&2 + exit 1;; +esac + +exit 0 + +@DPATCH@ +diff -urNad libid3tag-0.15.1b/utf16.c /tmp/dpep.tKvO7a/libid3tag-0.15.1b/utf16.c +--- libid3tag-0.15.1b/utf16.c 2006-01-13 15:26:29.000000000 +0100 ++++ /tmp/dpep.tKvO7a/libid3tag-0.15.1b/utf16.c 2006-01-13 15:27:19.000000000 +0100 +@@ -282,5 +282,18 @@ + + free(utf16); + ++ if (end == *ptr && length % 2 != 0) ++ { ++ /* We were called with a bogus length. It should always ++ * be an even number. We can deal with this in a few ways: ++ * - Always give an error. ++ * - Try and parse as much as we can and ++ * - return an error if we're called again when we ++ * already tried to parse everything we can. ++ * - tell that we parsed it, which is what we do here. ++ */ ++ (*ptr)++; ++ } ++ + return ucs4; + } diff --git a/ThirdParty/libid3tag/patches/11_unknown_encoding.diff b/ThirdParty/libid3tag/patches/11_unknown_encoding.diff new file mode 100644 index 000000000..7387f2f7d --- /dev/null +++ b/ThirdParty/libid3tag/patches/11_unknown_encoding.diff @@ -0,0 +1,37 @@ +#! /bin/sh /usr/share/dpatch/dpatch-run +## 11_unknown_encoding.dpatch by Andreas Henriksson +## +## All lines beginning with `## DP:' are a description of the patch. +## DP: In case of an unknown/invalid encoding, id3_parse_string() will +## DP: return NULL, but the return value wasn't checked resulting +## DP: in segfault in id3_ucs4_length(). This is the only place +## DP: the return value wasn't checked. + +@DPATCH@ +diff -urNad libid3tag-0.15.1b~/compat.gperf libid3tag-0.15.1b/compat.gperf +--- libid3tag-0.15.1b~/compat.gperf 2004-01-23 09:41:32.000000000 +0000 ++++ libid3tag-0.15.1b/compat.gperf 2007-01-14 14:36:53.000000000 +0000 +@@ -236,6 +236,10 @@ + + encoding = id3_parse_uint(&data, 1); + string = id3_parse_string(&data, end - data, encoding, 0); ++ if (!string) ++ { ++ continue; ++ } + + if (id3_ucs4_length(string) < 4) { + free(string); +diff -urNad libid3tag-0.15.1b~/parse.c libid3tag-0.15.1b/parse.c +--- libid3tag-0.15.1b~/parse.c 2004-01-23 09:41:32.000000000 +0000 ++++ libid3tag-0.15.1b/parse.c 2007-01-14 14:37:34.000000000 +0000 +@@ -165,6 +165,9 @@ + case ID3_FIELD_TEXTENCODING_UTF_8: + ucs4 = id3_utf8_deserialize(ptr, length); + break; ++ default: ++ /* FIXME: Unknown encoding! Print warning? */ ++ return NULL; + } + + if (ucs4 && !full) { diff --git a/ThirdParty/libid3tag/patches/CVE-2008-2109.patch b/ThirdParty/libid3tag/patches/CVE-2008-2109.patch new file mode 100644 index 000000000..26c54c5d2 --- /dev/null +++ b/ThirdParty/libid3tag/patches/CVE-2008-2109.patch @@ -0,0 +1,11 @@ +--- field.c.orig 2008-05-05 09:49:15.000000000 -0400 ++++ field.c 2008-05-05 09:49:25.000000000 -0400 +@@ -291,7 +291,7 @@ + + end = *ptr + length; + +- while (end - *ptr > 0) { ++ while (end - *ptr > 0 && **ptr != '\0') { + ucs4 = id3_parse_string(ptr, end - *ptr, *encoding, 0); + if (ucs4 == 0) + goto fail; diff --git a/ThirdParty/libid3tag/patches/libid3tag-gperf.patch b/ThirdParty/libid3tag/patches/libid3tag-gperf.patch new file mode 100644 index 000000000..9dfad6c72 --- /dev/null +++ b/ThirdParty/libid3tag/patches/libid3tag-gperf.patch @@ -0,0 +1,26 @@ +Index: libid3tag-0.15.1b/frametype.h +=================================================================== +--- libid3tag-0.15.1b.orig/frametype.h ++++ libid3tag-0.15.1b/frametype.h +@@ -37,6 +37,6 @@ extern struct id3_frametype const id3_fr + extern struct id3_frametype const id3_frametype_obsolete; + + struct id3_frametype const *id3_frametype_lookup(register char const *, +- register unsigned int); ++ register size_t); + + # endif +Index: libid3tag-0.15.1b/compat.h +=================================================================== +--- libid3tag-0.15.1b.orig/compat.h ++++ libid3tag-0.15.1b/compat.h +@@ -34,7 +34,7 @@ struct id3_compat { + }; + + struct id3_compat const *id3_compat_lookup(register char const *, +- register unsigned int); ++ register size_t); + + int id3_compat_fixup(struct id3_tag *); + + diff --git a/ThirdParty/libmad/README.md b/ThirdParty/libmad/README.md new file mode 100644 index 000000000..8e6dbd2e8 --- /dev/null +++ b/ThirdParty/libmad/README.md @@ -0,0 +1,12 @@ +Built with the Homebrew defaults, sort of: + +``` +touch NEWS +touch AUTHORS +touch ChangeLog +autoreconf -fiv +./configure --disable-debugging --enable-fpm=64bit +make -j8 CFLAGS="-Os -arch x86_64 -arch arm64 -mmacosx-version-min=10.12" LDFLAGS="-arch x86_64 -arch arm64 -mmacosx-version-min=10.12" +``` + +Version 0.15.1b was used. diff --git a/ThirdParty/libmad/include/MAD/mad.h b/ThirdParty/libmad/include/MAD/mad.h new file mode 100644 index 000000000..9a449cd47 --- /dev/null +++ b/ThirdParty/libmad/include/MAD/mad.h @@ -0,0 +1,964 @@ +/* + * libmad - MPEG audio decoder library + * Copyright (C) 2000-2004 Underbit Technologies, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * If you would like to negotiate alternate licensing terms, you may do + * so by contacting: Underbit Technologies, Inc. + */ + +# ifdef __cplusplus +extern "C" { +# endif + +# define FPM_64BIT + + + +# define SIZEOF_INT 4 +# define SIZEOF_LONG 8 +# define SIZEOF_LONG_LONG 8 + + +/* Id: version.h,v 1.26 2004/01/23 09:41:33 rob Exp */ + +# ifndef LIBMAD_VERSION_H +# define LIBMAD_VERSION_H + +# define MAD_VERSION_MAJOR 0 +# define MAD_VERSION_MINOR 15 +# define MAD_VERSION_PATCH 1 +# define MAD_VERSION_EXTRA " (beta)" + +# define MAD_VERSION_STRINGIZE(str) #str +# define MAD_VERSION_STRING(num) MAD_VERSION_STRINGIZE(num) + +# define MAD_VERSION MAD_VERSION_STRING(MAD_VERSION_MAJOR) "." \ + MAD_VERSION_STRING(MAD_VERSION_MINOR) "." \ + MAD_VERSION_STRING(MAD_VERSION_PATCH) \ + MAD_VERSION_EXTRA + +# define MAD_PUBLISHYEAR "2000-2004" +# define MAD_AUTHOR "Underbit Technologies, Inc." +# define MAD_EMAIL "info@underbit.com" + +extern char const mad_version[]; +extern char const mad_copyright[]; +extern char const mad_author[]; +extern char const mad_build[]; + +# endif + +/* Id: fixed.h,v 1.38 2004/02/17 02:02:03 rob Exp */ + +# ifndef LIBMAD_FIXED_H +# define LIBMAD_FIXED_H + +# if SIZEOF_INT >= 4 +typedef signed int mad_fixed_t; + +typedef signed int mad_fixed64hi_t; +typedef unsigned int mad_fixed64lo_t; +# else +typedef signed long mad_fixed_t; + +typedef signed long mad_fixed64hi_t; +typedef unsigned long mad_fixed64lo_t; +# endif + +# if defined(_MSC_VER) +# define mad_fixed64_t signed __int64 +# elif 1 || defined(__GNUC__) +# define mad_fixed64_t signed long long +# endif + +# if defined(FPM_FLOAT) +typedef double mad_sample_t; +# else +typedef mad_fixed_t mad_sample_t; +# endif + +/* + * Fixed-point format: 0xABBBBBBB + * A == whole part (sign + 3 bits) + * B == fractional part (28 bits) + * + * Values are signed two's complement, so the effective range is: + * 0x80000000 to 0x7fffffff + * -8.0 to +7.9999999962747097015380859375 + * + * The smallest representable value is: + * 0x00000001 == 0.0000000037252902984619140625 (i.e. about 3.725e-9) + * + * 28 bits of fractional accuracy represent about + * 8.6 digits of decimal accuracy. + * + * Fixed-point numbers can be added or subtracted as normal + * integers, but multiplication requires shifting the 64-bit result + * from 56 fractional bits back to 28 (and rounding.) + * + * Changing the definition of MAD_F_FRACBITS is only partially + * supported, and must be done with care. + */ + +# define MAD_F_FRACBITS 28 + +# if MAD_F_FRACBITS == 28 +# define MAD_F(x) ((mad_fixed_t) (x##L)) +# else +# if MAD_F_FRACBITS < 28 +# warning "MAD_F_FRACBITS < 28" +# define MAD_F(x) ((mad_fixed_t) \ + (((x##L) + \ + (1L << (28 - MAD_F_FRACBITS - 1))) >> \ + (28 - MAD_F_FRACBITS))) +# elif MAD_F_FRACBITS > 28 +# error "MAD_F_FRACBITS > 28 not currently supported" +# define MAD_F(x) ((mad_fixed_t) \ + ((x##L) << (MAD_F_FRACBITS - 28))) +# endif +# endif + +# define MAD_F_MIN ((mad_fixed_t) -0x80000000L) +# define MAD_F_MAX ((mad_fixed_t) +0x7fffffffL) + +# define MAD_F_ONE MAD_F(0x10000000) + +# define mad_f_tofixed(x) ((mad_fixed_t) \ + ((x) * (double) (1L << MAD_F_FRACBITS) + 0.5)) +# define mad_f_todouble(x) ((double) \ + ((x) / (double) (1L << MAD_F_FRACBITS))) + +# define mad_f_intpart(x) ((x) >> MAD_F_FRACBITS) +# define mad_f_fracpart(x) ((x) & ((1L << MAD_F_FRACBITS) - 1)) + /* (x should be positive) */ + +# define mad_f_fromint(x) ((x) << MAD_F_FRACBITS) + +# define mad_f_add(x, y) ((x) + (y)) +# define mad_f_sub(x, y) ((x) - (y)) + +# if defined(FPM_FLOAT) +# error "FPM_FLOAT not yet supported" + +# undef MAD_F +# define MAD_F(x) mad_f_todouble(x) + +# define mad_f_mul(x, y) ((x) * (y)) +# define mad_f_scale64 + +# undef ASO_ZEROCHECK + +# elif defined(FPM_64BIT) + +/* + * This version should be the most accurate if 64-bit types are supported by + * the compiler, although it may not be the most efficient. + */ +# if defined(OPT_ACCURACY) +# define mad_f_mul(x, y) \ + ((mad_fixed_t) \ + ((((mad_fixed64_t) (x) * (y)) + \ + (1L << (MAD_F_SCALEBITS - 1))) >> MAD_F_SCALEBITS)) +# else +# define mad_f_mul(x, y) \ + ((mad_fixed_t) (((mad_fixed64_t) (x) * (y)) >> MAD_F_SCALEBITS)) +# endif + +# define MAD_F_SCALEBITS MAD_F_FRACBITS + +/* --- Intel --------------------------------------------------------------- */ + +# elif defined(FPM_INTEL) + +# if defined(_MSC_VER) +# pragma warning(push) +# pragma warning(disable: 4035) /* no return value */ +static __forceinline +mad_fixed_t mad_f_mul_inline(mad_fixed_t x, mad_fixed_t y) +{ + enum { + fracbits = MAD_F_FRACBITS + }; + + __asm { + mov eax, x + imul y + shrd eax, edx, fracbits + } + + /* implicit return of eax */ +} +# pragma warning(pop) + +# define mad_f_mul mad_f_mul_inline +# define mad_f_scale64 +# else +/* + * This Intel version is fast and accurate; the disposition of the least + * significant bit depends on OPT_ACCURACY via mad_f_scale64(). + */ +# define MAD_F_MLX(hi, lo, x, y) \ + asm ("imull %3" \ + : "=a" (lo), "=d" (hi) \ + : "%a" (x), "rm" (y) \ + : "cc") + +# if defined(OPT_ACCURACY) +/* + * This gives best accuracy but is not very fast. + */ +# define MAD_F_MLA(hi, lo, x, y) \ + ({ mad_fixed64hi_t __hi; \ + mad_fixed64lo_t __lo; \ + MAD_F_MLX(__hi, __lo, (x), (y)); \ + asm ("addl %2,%0\n\t" \ + "adcl %3,%1" \ + : "=rm" (lo), "=rm" (hi) \ + : "r" (__lo), "r" (__hi), "0" (lo), "1" (hi) \ + : "cc"); \ + }) +# endif /* OPT_ACCURACY */ + +# if defined(OPT_ACCURACY) +/* + * Surprisingly, this is faster than SHRD followed by ADC. + */ +# define mad_f_scale64(hi, lo) \ + ({ mad_fixed64hi_t __hi_; \ + mad_fixed64lo_t __lo_; \ + mad_fixed_t __result; \ + asm ("addl %4,%2\n\t" \ + "adcl %5,%3" \ + : "=rm" (__lo_), "=rm" (__hi_) \ + : "0" (lo), "1" (hi), \ + "ir" (1L << (MAD_F_SCALEBITS - 1)), "ir" (0) \ + : "cc"); \ + asm ("shrdl %3,%2,%1" \ + : "=rm" (__result) \ + : "0" (__lo_), "r" (__hi_), "I" (MAD_F_SCALEBITS) \ + : "cc"); \ + __result; \ + }) +# elif defined(OPT_INTEL) +/* + * Alternate Intel scaling that may or may not perform better. + */ +# define mad_f_scale64(hi, lo) \ + ({ mad_fixed_t __result; \ + asm ("shrl %3,%1\n\t" \ + "shll %4,%2\n\t" \ + "orl %2,%1" \ + : "=rm" (__result) \ + : "0" (lo), "r" (hi), \ + "I" (MAD_F_SCALEBITS), "I" (32 - MAD_F_SCALEBITS) \ + : "cc"); \ + __result; \ + }) +# else +# define mad_f_scale64(hi, lo) \ + ({ mad_fixed_t __result; \ + asm ("shrdl %3,%2,%1" \ + : "=rm" (__result) \ + : "0" (lo), "r" (hi), "I" (MAD_F_SCALEBITS) \ + : "cc"); \ + __result; \ + }) +# endif /* OPT_ACCURACY */ + +# define MAD_F_SCALEBITS MAD_F_FRACBITS +# endif + +/* --- ARM ----------------------------------------------------------------- */ + +# elif defined(FPM_ARM) + +/* + * This ARM V4 version is as accurate as FPM_64BIT but much faster. The + * least significant bit is properly rounded at no CPU cycle cost! + */ +# if 1 +/* + * This is faster than the default implementation via MAD_F_MLX() and + * mad_f_scale64(). + */ +# define mad_f_mul(x, y) \ + ({ mad_fixed64hi_t __hi; \ + mad_fixed64lo_t __lo; \ + mad_fixed_t __result; \ + asm ("smull %0, %1, %3, %4\n\t" \ + "movs %0, %0, lsr %5\n\t" \ + "adc %2, %0, %1, lsl %6" \ + : "=&r" (__lo), "=&r" (__hi), "=r" (__result) \ + : "%r" (x), "r" (y), \ + "M" (MAD_F_SCALEBITS), "M" (32 - MAD_F_SCALEBITS) \ + : "cc"); \ + __result; \ + }) +# endif + +# define MAD_F_MLX(hi, lo, x, y) \ + asm ("smull %0, %1, %2, %3" \ + : "=&r" (lo), "=&r" (hi) \ + : "%r" (x), "r" (y)) + +# define MAD_F_MLA(hi, lo, x, y) \ + asm ("smlal %0, %1, %2, %3" \ + : "+r" (lo), "+r" (hi) \ + : "%r" (x), "r" (y)) + +# define MAD_F_MLN(hi, lo) \ + asm ("rsbs %0, %2, #0\n\t" \ + "rsc %1, %3, #0" \ + : "=r" (lo), "=r" (hi) \ + : "0" (lo), "1" (hi) \ + : "cc") + +# define mad_f_scale64(hi, lo) \ + ({ mad_fixed_t __result; \ + asm ("movs %0, %1, lsr %3\n\t" \ + "adc %0, %0, %2, lsl %4" \ + : "=&r" (__result) \ + : "r" (lo), "r" (hi), \ + "M" (MAD_F_SCALEBITS), "M" (32 - MAD_F_SCALEBITS) \ + : "cc"); \ + __result; \ + }) + +# define MAD_F_SCALEBITS MAD_F_FRACBITS + +/* --- MIPS ---------------------------------------------------------------- */ + +# elif defined(FPM_MIPS) + +/* + * This MIPS version is fast and accurate; the disposition of the least + * significant bit depends on OPT_ACCURACY via mad_f_scale64(). + */ +# define MAD_F_MLX(hi, lo, x, y) \ + asm ("mult %2,%3" \ + : "=l" (lo), "=h" (hi) \ + : "%r" (x), "r" (y)) + +# if defined(HAVE_MADD_ASM) +# define MAD_F_MLA(hi, lo, x, y) \ + asm ("madd %2,%3" \ + : "+l" (lo), "+h" (hi) \ + : "%r" (x), "r" (y)) +# elif defined(HAVE_MADD16_ASM) +/* + * This loses significant accuracy due to the 16-bit integer limit in the + * multiply/accumulate instruction. + */ +# define MAD_F_ML0(hi, lo, x, y) \ + asm ("mult %2,%3" \ + : "=l" (lo), "=h" (hi) \ + : "%r" ((x) >> 12), "r" ((y) >> 16)) +# define MAD_F_MLA(hi, lo, x, y) \ + asm ("madd16 %2,%3" \ + : "+l" (lo), "+h" (hi) \ + : "%r" ((x) >> 12), "r" ((y) >> 16)) +# define MAD_F_MLZ(hi, lo) ((mad_fixed_t) (lo)) +# endif + +# if defined(OPT_SPEED) +# define mad_f_scale64(hi, lo) \ + ((mad_fixed_t) ((hi) << (32 - MAD_F_SCALEBITS))) +# define MAD_F_SCALEBITS MAD_F_FRACBITS +# endif + +/* --- SPARC --------------------------------------------------------------- */ + +# elif defined(FPM_SPARC) + +/* + * This SPARC V8 version is fast and accurate; the disposition of the least + * significant bit depends on OPT_ACCURACY via mad_f_scale64(). + */ +# define MAD_F_MLX(hi, lo, x, y) \ + asm ("smul %2, %3, %0\n\t" \ + "rd %%y, %1" \ + : "=r" (lo), "=r" (hi) \ + : "%r" (x), "rI" (y)) + +/* --- PowerPC ------------------------------------------------------------- */ + +# elif defined(FPM_PPC) + +/* + * This PowerPC version is fast and accurate; the disposition of the least + * significant bit depends on OPT_ACCURACY via mad_f_scale64(). + */ +# define MAD_F_MLX(hi, lo, x, y) \ + do { \ + asm ("mullw %0,%1,%2" \ + : "=r" (lo) \ + : "%r" (x), "r" (y)); \ + asm ("mulhw %0,%1,%2" \ + : "=r" (hi) \ + : "%r" (x), "r" (y)); \ + } \ + while (0) + +# if defined(OPT_ACCURACY) +/* + * This gives best accuracy but is not very fast. + */ +# define MAD_F_MLA(hi, lo, x, y) \ + ({ mad_fixed64hi_t __hi; \ + mad_fixed64lo_t __lo; \ + MAD_F_MLX(__hi, __lo, (x), (y)); \ + asm ("addc %0,%2,%3\n\t" \ + "adde %1,%4,%5" \ + : "=r" (lo), "=r" (hi) \ + : "%r" (lo), "r" (__lo), \ + "%r" (hi), "r" (__hi) \ + : "xer"); \ + }) +# endif + +# if defined(OPT_ACCURACY) +/* + * This is slower than the truncating version below it. + */ +# define mad_f_scale64(hi, lo) \ + ({ mad_fixed_t __result, __round; \ + asm ("rotrwi %0,%1,%2" \ + : "=r" (__result) \ + : "r" (lo), "i" (MAD_F_SCALEBITS)); \ + asm ("extrwi %0,%1,1,0" \ + : "=r" (__round) \ + : "r" (__result)); \ + asm ("insrwi %0,%1,%2,0" \ + : "+r" (__result) \ + : "r" (hi), "i" (MAD_F_SCALEBITS)); \ + asm ("add %0,%1,%2" \ + : "=r" (__result) \ + : "%r" (__result), "r" (__round)); \ + __result; \ + }) +# else +# define mad_f_scale64(hi, lo) \ + ({ mad_fixed_t __result; \ + asm ("rotrwi %0,%1,%2" \ + : "=r" (__result) \ + : "r" (lo), "i" (MAD_F_SCALEBITS)); \ + asm ("insrwi %0,%1,%2,0" \ + : "+r" (__result) \ + : "r" (hi), "i" (MAD_F_SCALEBITS)); \ + __result; \ + }) +# endif + +# define MAD_F_SCALEBITS MAD_F_FRACBITS + +/* --- Default ------------------------------------------------------------- */ + +# elif defined(FPM_DEFAULT) + +/* + * This version is the most portable but it loses significant accuracy. + * Furthermore, accuracy is biased against the second argument, so care + * should be taken when ordering operands. + * + * The scale factors are constant as this is not used with SSO. + * + * Pre-rounding is required to stay within the limits of compliance. + */ +# if defined(OPT_SPEED) +# define mad_f_mul(x, y) (((x) >> 12) * ((y) >> 16)) +# else +# define mad_f_mul(x, y) ((((x) + (1L << 11)) >> 12) * \ + (((y) + (1L << 15)) >> 16)) +# endif + +/* ------------------------------------------------------------------------- */ + +# else +# error "no FPM selected" +# endif + +/* default implementations */ + +# if !defined(mad_f_mul) +# define mad_f_mul(x, y) \ + ({ register mad_fixed64hi_t __hi; \ + register mad_fixed64lo_t __lo; \ + MAD_F_MLX(__hi, __lo, (x), (y)); \ + mad_f_scale64(__hi, __lo); \ + }) +# endif + +# if !defined(MAD_F_MLA) +# define MAD_F_ML0(hi, lo, x, y) ((lo) = mad_f_mul((x), (y))) +# define MAD_F_MLA(hi, lo, x, y) ((lo) += mad_f_mul((x), (y))) +# define MAD_F_MLN(hi, lo) ((lo) = -(lo)) +# define MAD_F_MLZ(hi, lo) ((void) (hi), (mad_fixed_t) (lo)) +# endif + +# if !defined(MAD_F_ML0) +# define MAD_F_ML0(hi, lo, x, y) MAD_F_MLX((hi), (lo), (x), (y)) +# endif + +# if !defined(MAD_F_MLN) +# define MAD_F_MLN(hi, lo) ((hi) = ((lo) = -(lo)) ? ~(hi) : -(hi)) +# endif + +# if !defined(MAD_F_MLZ) +# define MAD_F_MLZ(hi, lo) mad_f_scale64((hi), (lo)) +# endif + +# if !defined(mad_f_scale64) +# if defined(OPT_ACCURACY) +# define mad_f_scale64(hi, lo) \ + ((((mad_fixed_t) \ + (((hi) << (32 - (MAD_F_SCALEBITS - 1))) | \ + ((lo) >> (MAD_F_SCALEBITS - 1)))) + 1) >> 1) +# else +# define mad_f_scale64(hi, lo) \ + ((mad_fixed_t) \ + (((hi) << (32 - MAD_F_SCALEBITS)) | \ + ((lo) >> MAD_F_SCALEBITS))) +# endif +# define MAD_F_SCALEBITS MAD_F_FRACBITS +# endif + +/* C routines */ + +mad_fixed_t mad_f_abs(mad_fixed_t); +mad_fixed_t mad_f_div(mad_fixed_t, mad_fixed_t); + +# endif + +/* Id: bit.h,v 1.12 2004/01/23 09:41:32 rob Exp */ + +# ifndef LIBMAD_BIT_H +# define LIBMAD_BIT_H + +struct mad_bitptr { + unsigned char const *byte; + unsigned short cache; + unsigned short left; +}; + +void mad_bit_init(struct mad_bitptr *, unsigned char const *); + +# define mad_bit_finish(bitptr) /* nothing */ + +unsigned int mad_bit_length(struct mad_bitptr const *, + struct mad_bitptr const *); + +# define mad_bit_bitsleft(bitptr) ((bitptr)->left) +unsigned char const *mad_bit_nextbyte(struct mad_bitptr const *); + +void mad_bit_skip(struct mad_bitptr *, unsigned int); +unsigned long mad_bit_read(struct mad_bitptr *, unsigned int); +void mad_bit_write(struct mad_bitptr *, unsigned int, unsigned long); + +unsigned short mad_bit_crc(struct mad_bitptr, unsigned int, unsigned short); + +# endif + +/* Id: timer.h,v 1.16 2004/01/23 09:41:33 rob Exp */ + +# ifndef LIBMAD_TIMER_H +# define LIBMAD_TIMER_H + +typedef struct { + signed long seconds; /* whole seconds */ + unsigned long fraction; /* 1/MAD_TIMER_RESOLUTION seconds */ +} mad_timer_t; + +extern mad_timer_t const mad_timer_zero; + +# define MAD_TIMER_RESOLUTION 352800000UL + +enum mad_units { + MAD_UNITS_HOURS = -2, + MAD_UNITS_MINUTES = -1, + MAD_UNITS_SECONDS = 0, + + /* metric units */ + + MAD_UNITS_DECISECONDS = 10, + MAD_UNITS_CENTISECONDS = 100, + MAD_UNITS_MILLISECONDS = 1000, + + /* audio sample units */ + + MAD_UNITS_8000_HZ = 8000, + MAD_UNITS_11025_HZ = 11025, + MAD_UNITS_12000_HZ = 12000, + + MAD_UNITS_16000_HZ = 16000, + MAD_UNITS_22050_HZ = 22050, + MAD_UNITS_24000_HZ = 24000, + + MAD_UNITS_32000_HZ = 32000, + MAD_UNITS_44100_HZ = 44100, + MAD_UNITS_48000_HZ = 48000, + + /* video frame/field units */ + + MAD_UNITS_24_FPS = 24, + MAD_UNITS_25_FPS = 25, + MAD_UNITS_30_FPS = 30, + MAD_UNITS_48_FPS = 48, + MAD_UNITS_50_FPS = 50, + MAD_UNITS_60_FPS = 60, + + /* CD audio frames */ + + MAD_UNITS_75_FPS = 75, + + /* video drop-frame units */ + + MAD_UNITS_23_976_FPS = -24, + MAD_UNITS_24_975_FPS = -25, + MAD_UNITS_29_97_FPS = -30, + MAD_UNITS_47_952_FPS = -48, + MAD_UNITS_49_95_FPS = -50, + MAD_UNITS_59_94_FPS = -60 +}; + +# define mad_timer_reset(timer) ((void) (*(timer) = mad_timer_zero)) + +int mad_timer_compare(mad_timer_t, mad_timer_t); + +# define mad_timer_sign(timer) mad_timer_compare((timer), mad_timer_zero) + +void mad_timer_negate(mad_timer_t *); +mad_timer_t mad_timer_abs(mad_timer_t); + +void mad_timer_set(mad_timer_t *, unsigned long, unsigned long, unsigned long); +void mad_timer_add(mad_timer_t *, mad_timer_t); +void mad_timer_multiply(mad_timer_t *, signed long); + +signed long mad_timer_count(mad_timer_t, enum mad_units); +unsigned long mad_timer_fraction(mad_timer_t, unsigned long); +void mad_timer_string(mad_timer_t, char *, char const *, + enum mad_units, enum mad_units, unsigned long); + +# endif + +/* Id: stream.h,v 1.20 2004/02/05 09:02:39 rob Exp */ + +# ifndef LIBMAD_STREAM_H +# define LIBMAD_STREAM_H + + +# define MAD_BUFFER_GUARD 8 +# define MAD_BUFFER_MDLEN (511 + 2048 + MAD_BUFFER_GUARD) + +enum mad_error { + MAD_ERROR_NONE = 0x0000, /* no error */ + + MAD_ERROR_BUFLEN = 0x0001, /* input buffer too small (or EOF) */ + MAD_ERROR_BUFPTR = 0x0002, /* invalid (null) buffer pointer */ + + MAD_ERROR_NOMEM = 0x0031, /* not enough memory */ + + MAD_ERROR_LOSTSYNC = 0x0101, /* lost synchronization */ + MAD_ERROR_BADLAYER = 0x0102, /* reserved header layer value */ + MAD_ERROR_BADBITRATE = 0x0103, /* forbidden bitrate value */ + MAD_ERROR_BADSAMPLERATE = 0x0104, /* reserved sample frequency value */ + MAD_ERROR_BADEMPHASIS = 0x0105, /* reserved emphasis value */ + + MAD_ERROR_BADCRC = 0x0201, /* CRC check failed */ + MAD_ERROR_BADBITALLOC = 0x0211, /* forbidden bit allocation value */ + MAD_ERROR_BADSCALEFACTOR = 0x0221, /* bad scalefactor index */ + MAD_ERROR_BADMODE = 0x0222, /* bad bitrate/mode combination */ + MAD_ERROR_BADFRAMELEN = 0x0231, /* bad frame length */ + MAD_ERROR_BADBIGVALUES = 0x0232, /* bad big_values count */ + MAD_ERROR_BADBLOCKTYPE = 0x0233, /* reserved block_type */ + MAD_ERROR_BADSCFSI = 0x0234, /* bad scalefactor selection info */ + MAD_ERROR_BADDATAPTR = 0x0235, /* bad main_data_begin pointer */ + MAD_ERROR_BADPART3LEN = 0x0236, /* bad audio data length */ + MAD_ERROR_BADHUFFTABLE = 0x0237, /* bad Huffman table select */ + MAD_ERROR_BADHUFFDATA = 0x0238, /* Huffman data overrun */ + MAD_ERROR_BADSTEREO = 0x0239 /* incompatible block_type for JS */ +}; + +# define MAD_RECOVERABLE(error) ((error) & 0xff00) + +struct mad_stream { + unsigned char const *buffer; /* input bitstream buffer */ + unsigned char const *bufend; /* end of buffer */ + unsigned long skiplen; /* bytes to skip before next frame */ + + int sync; /* stream sync found */ + unsigned long freerate; /* free bitrate (fixed) */ + + unsigned char const *this_frame; /* start of current frame */ + unsigned char const *next_frame; /* start of next frame */ + struct mad_bitptr ptr; /* current processing bit pointer */ + + struct mad_bitptr anc_ptr; /* ancillary bits pointer */ + unsigned int anc_bitlen; /* number of ancillary bits */ + + unsigned char (*main_data)[MAD_BUFFER_MDLEN]; + /* Layer III main_data() */ + unsigned int md_len; /* bytes in main_data */ + + int options; /* decoding options (see below) */ + enum mad_error error; /* error code (see above) */ +}; + +enum { + MAD_OPTION_IGNORECRC = 0x0001, /* ignore CRC errors */ + MAD_OPTION_HALFSAMPLERATE = 0x0002 /* generate PCM at 1/2 sample rate */ +# if 0 /* not yet implemented */ + MAD_OPTION_LEFTCHANNEL = 0x0010, /* decode left channel only */ + MAD_OPTION_RIGHTCHANNEL = 0x0020, /* decode right channel only */ + MAD_OPTION_SINGLECHANNEL = 0x0030 /* combine channels */ +# endif +}; + +void mad_stream_init(struct mad_stream *); +void mad_stream_finish(struct mad_stream *); + +# define mad_stream_options(stream, opts) \ + ((void) ((stream)->options = (opts))) + +void mad_stream_buffer(struct mad_stream *, + unsigned char const *, unsigned long); +void mad_stream_skip(struct mad_stream *, unsigned long); + +int mad_stream_sync(struct mad_stream *); + +char const *mad_stream_errorstr(struct mad_stream const *); + +# endif + +/* Id: frame.h,v 1.20 2004/01/23 09:41:32 rob Exp */ + +# ifndef LIBMAD_FRAME_H +# define LIBMAD_FRAME_H + + +enum mad_layer { + MAD_LAYER_I = 1, /* Layer I */ + MAD_LAYER_II = 2, /* Layer II */ + MAD_LAYER_III = 3 /* Layer III */ +}; + +enum mad_mode { + MAD_MODE_SINGLE_CHANNEL = 0, /* single channel */ + MAD_MODE_DUAL_CHANNEL = 1, /* dual channel */ + MAD_MODE_JOINT_STEREO = 2, /* joint (MS/intensity) stereo */ + MAD_MODE_STEREO = 3 /* normal LR stereo */ +}; + +enum mad_emphasis { + MAD_EMPHASIS_NONE = 0, /* no emphasis */ + MAD_EMPHASIS_50_15_US = 1, /* 50/15 microseconds emphasis */ + MAD_EMPHASIS_CCITT_J_17 = 3, /* CCITT J.17 emphasis */ + MAD_EMPHASIS_RESERVED = 2 /* unknown emphasis */ +}; + +struct mad_header { + enum mad_layer layer; /* audio layer (1, 2, or 3) */ + enum mad_mode mode; /* channel mode (see above) */ + int mode_extension; /* additional mode info */ + enum mad_emphasis emphasis; /* de-emphasis to use (see above) */ + + unsigned long bitrate; /* stream bitrate (bps) */ + unsigned int samplerate; /* sampling frequency (Hz) */ + + unsigned short crc_check; /* frame CRC accumulator */ + unsigned short crc_target; /* final target CRC checksum */ + + int flags; /* flags (see below) */ + int private_bits; /* private bits (see below) */ + + mad_timer_t duration; /* audio playing time of frame */ +}; + +struct mad_frame { + struct mad_header header; /* MPEG audio header */ + + int options; /* decoding options (from stream) */ + + mad_fixed_t sbsample[2][36][32]; /* synthesis subband filter samples */ + mad_fixed_t (*overlap)[2][32][18]; /* Layer III block overlap data */ +}; + +# define MAD_NCHANNELS(header) ((header)->mode ? 2 : 1) +# define MAD_NSBSAMPLES(header) \ + ((header)->layer == MAD_LAYER_I ? 12 : \ + (((header)->layer == MAD_LAYER_III && \ + ((header)->flags & MAD_FLAG_LSF_EXT)) ? 18 : 36)) + +enum { + MAD_FLAG_NPRIVATE_III = 0x0007, /* number of Layer III private bits */ + MAD_FLAG_INCOMPLETE = 0x0008, /* header but not data is decoded */ + + MAD_FLAG_PROTECTION = 0x0010, /* frame has CRC protection */ + MAD_FLAG_COPYRIGHT = 0x0020, /* frame is copyright */ + MAD_FLAG_ORIGINAL = 0x0040, /* frame is original (else copy) */ + MAD_FLAG_PADDING = 0x0080, /* frame has additional slot */ + + MAD_FLAG_I_STEREO = 0x0100, /* uses intensity joint stereo */ + MAD_FLAG_MS_STEREO = 0x0200, /* uses middle/side joint stereo */ + MAD_FLAG_FREEFORMAT = 0x0400, /* uses free format bitrate */ + + MAD_FLAG_LSF_EXT = 0x1000, /* lower sampling freq. extension */ + MAD_FLAG_MC_EXT = 0x2000, /* multichannel audio extension */ + MAD_FLAG_MPEG_2_5_EXT = 0x4000 /* MPEG 2.5 (unofficial) extension */ +}; + +enum { + MAD_PRIVATE_HEADER = 0x0100, /* header private bit */ + MAD_PRIVATE_III = 0x001f /* Layer III private bits (up to 5) */ +}; + +void mad_header_init(struct mad_header *); + +# define mad_header_finish(header) /* nothing */ + +int mad_header_decode(struct mad_header *, struct mad_stream *); + +void mad_frame_init(struct mad_frame *); +void mad_frame_finish(struct mad_frame *); + +int mad_frame_decode(struct mad_frame *, struct mad_stream *); + +void mad_frame_mute(struct mad_frame *); + +# endif + +/* Id: synth.h,v 1.15 2004/01/23 09:41:33 rob Exp */ + +# ifndef LIBMAD_SYNTH_H +# define LIBMAD_SYNTH_H + + +struct mad_pcm { + unsigned int samplerate; /* sampling frequency (Hz) */ + unsigned short channels; /* number of channels */ + unsigned short length; /* number of samples per channel */ + mad_fixed_t samples[2][1152]; /* PCM output samples [ch][sample] */ +}; + +struct mad_synth { + mad_fixed_t filter[2][2][2][16][8]; /* polyphase filterbank outputs */ + /* [ch][eo][peo][s][v] */ + + unsigned int phase; /* current processing phase */ + + struct mad_pcm pcm; /* PCM output */ +}; + +/* single channel PCM selector */ +enum { + MAD_PCM_CHANNEL_SINGLE = 0 +}; + +/* dual channel PCM selector */ +enum { + MAD_PCM_CHANNEL_DUAL_1 = 0, + MAD_PCM_CHANNEL_DUAL_2 = 1 +}; + +/* stereo PCM selector */ +enum { + MAD_PCM_CHANNEL_STEREO_LEFT = 0, + MAD_PCM_CHANNEL_STEREO_RIGHT = 1 +}; + +void mad_synth_init(struct mad_synth *); + +# define mad_synth_finish(synth) /* nothing */ + +void mad_synth_mute(struct mad_synth *); + +void mad_synth_frame(struct mad_synth *, struct mad_frame const *); + +# endif + +/* Id: decoder.h,v 1.17 2004/01/23 09:41:32 rob Exp */ + +# ifndef LIBMAD_DECODER_H +# define LIBMAD_DECODER_H + + +enum mad_decoder_mode { + MAD_DECODER_MODE_SYNC = 0, + MAD_DECODER_MODE_ASYNC +}; + +enum mad_flow { + MAD_FLOW_CONTINUE = 0x0000, /* continue normally */ + MAD_FLOW_STOP = 0x0010, /* stop decoding normally */ + MAD_FLOW_BREAK = 0x0011, /* stop decoding and signal an error */ + MAD_FLOW_IGNORE = 0x0020 /* ignore the current frame */ +}; + +struct mad_decoder { + enum mad_decoder_mode mode; + + int options; + + struct { + long pid; + int in; + int out; + } async; + + struct { + struct mad_stream stream; + struct mad_frame frame; + struct mad_synth synth; + } *sync; + + void *cb_data; + + enum mad_flow (*input_func)(void *, struct mad_stream *); + enum mad_flow (*header_func)(void *, struct mad_header const *); + enum mad_flow (*filter_func)(void *, + struct mad_stream const *, struct mad_frame *); + enum mad_flow (*output_func)(void *, + struct mad_header const *, struct mad_pcm *); + enum mad_flow (*error_func)(void *, struct mad_stream *, struct mad_frame *); + enum mad_flow (*message_func)(void *, void *, unsigned int *); +}; + +void mad_decoder_init(struct mad_decoder *, void *, + enum mad_flow (*)(void *, struct mad_stream *), + enum mad_flow (*)(void *, struct mad_header const *), + enum mad_flow (*)(void *, + struct mad_stream const *, + struct mad_frame *), + enum mad_flow (*)(void *, + struct mad_header const *, + struct mad_pcm *), + enum mad_flow (*)(void *, + struct mad_stream *, + struct mad_frame *), + enum mad_flow (*)(void *, void *, unsigned int *)); +int mad_decoder_finish(struct mad_decoder *); + +# define mad_decoder_options(decoder, opts) \ + ((void) ((decoder)->options = (opts))) + +int mad_decoder_run(struct mad_decoder *, enum mad_decoder_mode); +int mad_decoder_message(struct mad_decoder *, void *, unsigned int *); + +# endif + +# ifdef __cplusplus +} +# endif diff --git a/ThirdParty/libmad/lib/libmad.a b/ThirdParty/libmad/lib/libmad.a new file mode 100644 index 000000000..4122a9d1d Binary files /dev/null and b/ThirdParty/libmad/lib/libmad.a differ