Brought back the MAD plugin from death
Now Cog supports freeformat MP3 once again. The plugin has been extended to include sample accurate seeking, accurate length probing of files missing headers, and iTunes gapless info reading using libid3tag. Signed-off-by: Christopher Snowhill <kode54@gmail.com>CQTexperiment
parent
1da6cf2557
commit
19556cc630
|
@ -134,6 +134,7 @@
|
||||||
836FB5A718206F2500B3AD2D /* Hively.bundle in CopyFiles */ = {isa = PBXBuildFile; fileRef = 836FB5471820538800B3AD2D /* Hively.bundle */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
|
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 */; };
|
8370D73D277419F700245CE0 /* SQLiteStore.m in Sources */ = {isa = PBXBuildFile; fileRef = 8370D73C277419F700245CE0 /* SQLiteStore.m */; };
|
||||||
8370D73F2775AE1300245CE0 /* libsqlite3.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 8370D73E2775AE1300245CE0 /* libsqlite3.tbd */; };
|
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 */; };
|
8377C66327B8CF6300E8BC0F /* SpectrumView.m in Sources */ = {isa = PBXBuildFile; fileRef = 8377C66127B8CF6300E8BC0F /* SpectrumView.m */; };
|
||||||
8377C6B927B900F000E8BC0F /* SpectrumItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 8377C6B827B900F000E8BC0F /* SpectrumItem.m */; };
|
8377C6B927B900F000E8BC0F /* SpectrumItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 8377C6B827B900F000E8BC0F /* SpectrumItem.m */; };
|
||||||
8381A09227C5F72F00A1C530 /* SHA256Digest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8381A09127C5F72F00A1C530 /* SHA256Digest.m */; };
|
8381A09227C5F72F00A1C530 /* SHA256Digest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8381A09127C5F72F00A1C530 /* SHA256Digest.m */; };
|
||||||
|
@ -518,6 +519,20 @@
|
||||||
remoteGlobalIDString = 836FB52C1820538700B3AD2D;
|
remoteGlobalIDString = 836FB52C1820538700B3AD2D;
|
||||||
remoteInfo = Hively;
|
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 */ = {
|
8375B36117FFEF010092A79F /* PBXContainerItemProxy */ = {
|
||||||
isa = PBXContainerItemProxy;
|
isa = PBXContainerItemProxy;
|
||||||
containerPortal = 8359FF2C17FEF35C0060F3ED /* ArchiveSource.xcodeproj */;
|
containerPortal = 8359FF2C17FEF35C0060F3ED /* ArchiveSource.xcodeproj */;
|
||||||
|
@ -670,6 +685,7 @@
|
||||||
dstPath = "";
|
dstPath = "";
|
||||||
dstSubfolderSpec = 13;
|
dstSubfolderSpec = 13;
|
||||||
files = (
|
files = (
|
||||||
|
8372C93D27C7895300E250C9 /* MAD.bundle in CopyFiles */,
|
||||||
83489C6B2782F78700BDCEA2 /* libvgmPlayer.bundle in CopyFiles */,
|
83489C6B2782F78700BDCEA2 /* libvgmPlayer.bundle in CopyFiles */,
|
||||||
83293070277886250010C07E /* OpenMPTOld.bundle in CopyFiles */,
|
83293070277886250010C07E /* OpenMPTOld.bundle in CopyFiles */,
|
||||||
834D794020E4EFEF00C4A5CC /* VorbisPlugin.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 = "<group>"; };
|
8370D739277419D200245CE0 /* SQLiteStore.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SQLiteStore.h; sourceTree = "<group>"; };
|
||||||
8370D73C277419F700245CE0 /* SQLiteStore.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SQLiteStore.m; sourceTree = "<group>"; };
|
8370D73C277419F700245CE0 /* SQLiteStore.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SQLiteStore.m; sourceTree = "<group>"; };
|
||||||
8370D73E2775AE1300245CE0 /* libsqlite3.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libsqlite3.tbd; path = usr/lib/libsqlite3.tbd; sourceTree = SDKROOT; };
|
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 = "<group>"; };
|
||||||
8375B05117FFEA400092A79F /* OpusPlugin.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = OpusPlugin.xcodeproj; path = Plugins/Opus/OpusPlugin.xcodeproj; sourceTree = "<group>"; };
|
8375B05117FFEA400092A79F /* OpusPlugin.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = OpusPlugin.xcodeproj; path = Plugins/Opus/OpusPlugin.xcodeproj; sourceTree = "<group>"; };
|
||||||
8377C66127B8CF6300E8BC0F /* SpectrumView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SpectrumView.m; path = Visualization/SpectrumView.m; sourceTree = "<group>"; };
|
8377C66127B8CF6300E8BC0F /* SpectrumView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SpectrumView.m; path = Visualization/SpectrumView.m; sourceTree = "<group>"; };
|
||||||
8377C66227B8CF6300E8BC0F /* SpectrumView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SpectrumView.h; path = Visualization/SpectrumView.h; sourceTree = "<group>"; };
|
8377C66227B8CF6300E8BC0F /* SpectrumView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SpectrumView.h; path = Visualization/SpectrumView.h; sourceTree = "<group>"; };
|
||||||
|
@ -1285,6 +1302,7 @@
|
||||||
17C808830C3BD181005707C4 /* HTTPSource.xcodeproj */,
|
17C808830C3BD181005707C4 /* HTTPSource.xcodeproj */,
|
||||||
83489C4E2782F2DF00BDCEA2 /* libvgmPlayer.xcodeproj */,
|
83489C4E2782F2DF00BDCEA2 /* libvgmPlayer.xcodeproj */,
|
||||||
8E8D40820CBB036600135C1B /* M3u.xcodeproj */,
|
8E8D40820CBB036600135C1B /* M3u.xcodeproj */,
|
||||||
|
8372C92A27C785BD00E250C9 /* MAD.xcodeproj */,
|
||||||
83B0669C180D5668008E3612 /* MIDI.xcodeproj */,
|
83B0669C180D5668008E3612 /* MIDI.xcodeproj */,
|
||||||
17C8089E0C3BD1AB005707C4 /* Musepack.xcodeproj */,
|
17C8089E0C3BD1AB005707C4 /* Musepack.xcodeproj */,
|
||||||
83E5EFAC1FFEF78100659F0F /* OpenMPT.xcodeproj */,
|
83E5EFAC1FFEF78100659F0F /* OpenMPT.xcodeproj */,
|
||||||
|
@ -1767,6 +1785,14 @@
|
||||||
name = Products;
|
name = Products;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
8372C92B27C785BD00E250C9 /* Products */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
8372C93027C785BE00E250C9 /* MAD.bundle */,
|
||||||
|
);
|
||||||
|
name = Products;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
8377C66027B8CF2300E8BC0F /* Visualization */ = {
|
8377C66027B8CF2300E8BC0F /* Visualization */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
@ -1947,6 +1973,7 @@
|
||||||
buildRules = (
|
buildRules = (
|
||||||
);
|
);
|
||||||
dependencies = (
|
dependencies = (
|
||||||
|
8372C93C27C7893100E250C9 /* PBXTargetDependency */,
|
||||||
83489C6A2782F76900BDCEA2 /* PBXTargetDependency */,
|
83489C6A2782F76900BDCEA2 /* PBXTargetDependency */,
|
||||||
8329306F2778860C0010C07E /* PBXTargetDependency */,
|
8329306F2778860C0010C07E /* PBXTargetDependency */,
|
||||||
ED69CBC625BE32B40090B90D /* PBXTargetDependency */,
|
ED69CBC625BE32B40090B90D /* PBXTargetDependency */,
|
||||||
|
@ -2082,6 +2109,10 @@
|
||||||
ProductGroup = 8E8D40830CBB036600135C1B /* Products */;
|
ProductGroup = 8E8D40830CBB036600135C1B /* Products */;
|
||||||
ProjectRef = 8E8D40820CBB036600135C1B /* M3u.xcodeproj */;
|
ProjectRef = 8E8D40820CBB036600135C1B /* M3u.xcodeproj */;
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
ProductGroup = 8372C92B27C785BD00E250C9 /* Products */;
|
||||||
|
ProjectRef = 8372C92A27C785BD00E250C9 /* MAD.xcodeproj */;
|
||||||
|
},
|
||||||
{
|
{
|
||||||
ProductGroup = ED69CBB925BE328C0090B90D /* Products */;
|
ProductGroup = ED69CBB925BE328C0090B90D /* Products */;
|
||||||
ProjectRef = ED69CBB825BE328C0090B90D /* MASShortcut.xcodeproj */;
|
ProjectRef = ED69CBB825BE328C0090B90D /* MASShortcut.xcodeproj */;
|
||||||
|
@ -2305,6 +2336,13 @@
|
||||||
remoteRef = 836FB5461820538800B3AD2D /* PBXContainerItemProxy */;
|
remoteRef = 836FB5461820538800B3AD2D /* PBXContainerItemProxy */;
|
||||||
sourceTree = BUILT_PRODUCTS_DIR;
|
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 */ = {
|
83B066A1180D5669008E3612 /* MIDI.bundle */ = {
|
||||||
isa = PBXReferenceProxy;
|
isa = PBXReferenceProxy;
|
||||||
fileType = wrapper.cfbundle;
|
fileType = wrapper.cfbundle;
|
||||||
|
@ -2676,6 +2714,11 @@
|
||||||
name = Hively;
|
name = Hively;
|
||||||
targetProxy = 836FB5A518206F1500B3AD2D /* PBXContainerItemProxy */;
|
targetProxy = 836FB5A518206F1500B3AD2D /* PBXContainerItemProxy */;
|
||||||
};
|
};
|
||||||
|
8372C93C27C7893100E250C9 /* PBXTargetDependency */ = {
|
||||||
|
isa = PBXTargetDependency;
|
||||||
|
name = MAD;
|
||||||
|
targetProxy = 8372C93B27C7893100E250C9 /* PBXContainerItemProxy */;
|
||||||
|
};
|
||||||
8375B36217FFEF010092A79F /* PBXTargetDependency */ = {
|
8375B36217FFEF010092A79F /* PBXTargetDependency */ = {
|
||||||
isa = PBXTargetDependency;
|
isa = PBXTargetDependency;
|
||||||
name = ArchiveSource;
|
name = ArchiveSource;
|
||||||
|
|
|
@ -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 = "<group>"; };
|
||||||
|
8372C93427C7861300E250C9 /* MADDecoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MADDecoder.m; sourceTree = "<group>"; };
|
||||||
|
8372C93627C7863700E250C9 /* libmad.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libmad.a; path = ../../ThirdParty/libmad/lib/libmad.a; sourceTree = "<group>"; };
|
||||||
|
8372C93827C7865A00E250C9 /* Plugin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Plugin.h; path = ../../Audio/Plugin.h; sourceTree = "<group>"; };
|
||||||
|
8372C93927C7866B00E250C9 /* Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Logging.h; path = ../../Utils/Logging.h; sourceTree = "<group>"; };
|
||||||
|
8372C93A27C786DD00E250C9 /* HTTPSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HTTPSource.h; path = ../HTTPSource/HTTPSource.h; sourceTree = "<group>"; };
|
||||||
|
8372C93E27C7904800E250C9 /* libid3tag.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libid3tag.a; path = ../../ThirdParty/libid3tag/lib/libid3tag.a; sourceTree = "<group>"; };
|
||||||
|
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 = "<group>";
|
||||||
|
};
|
||||||
|
8372C92427C785BD00E250C9 /* Products */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
8372C92327C785BD00E250C9 /* MAD.bundle */,
|
||||||
|
);
|
||||||
|
name = Products;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
8372C94027C7959000E250C9 /* Frameworks */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
8372C94127C7959000E250C9 /* libz.tbd */,
|
||||||
|
);
|
||||||
|
name = Frameworks;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
/* 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 */;
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
//
|
||||||
|
// MADFile.h
|
||||||
|
// Cog
|
||||||
|
//
|
||||||
|
// Created by Vincent Spader on 6/17/06.
|
||||||
|
// Copyright 2006 Vincent Spader. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
#import "MAD/mad.h"
|
||||||
|
|
||||||
|
#import "Plugin.h"
|
||||||
|
|
||||||
|
#define INPUT_BUFFER_SIZE 5 * 8192
|
||||||
|
|
||||||
|
@interface MADDecoder : NSObject <CogDecoder> {
|
||||||
|
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<CogSource> _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
|
|
@ -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 <Accelerate/Accelerate.h>
|
||||||
|
|
||||||
|
@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<CogSource>)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
|
|
@ -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.
|
|
@ -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. <info@underbit.com>
|
||||||
|
*
|
||||||
|
* $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
|
Binary file not shown.
|
@ -0,0 +1,48 @@
|
||||||
|
#! /bin/sh -e
|
||||||
|
## 10_utf16.dpatch by <kurt@roeckx.be>
|
||||||
|
##
|
||||||
|
## 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;
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
#! /bin/sh /usr/share/dpatch/dpatch-run
|
||||||
|
## 11_unknown_encoding.dpatch by Andreas Henriksson <andreas@fatal.se>
|
||||||
|
##
|
||||||
|
## 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) {
|
|
@ -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;
|
|
@ -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 *);
|
||||||
|
|
||||||
|
|
|
@ -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.
|
|
@ -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. <info@underbit.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
# 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
|
Binary file not shown.
Loading…
Reference in New Issue