mirror of
https://github.com/claunia/cuetools.net.git
synced 2025-12-16 18:14:25 +00:00
initial checkin
This commit is contained in:
39
FLACDotNet/AssemblyInfo.cpp
Normal file
39
FLACDotNet/AssemblyInfo.cpp
Normal file
@@ -0,0 +1,39 @@
|
||||
|
||||
using namespace System;
|
||||
using namespace System::Reflection;
|
||||
using namespace System::Runtime::CompilerServices;
|
||||
using namespace System::Runtime::InteropServices;
|
||||
using namespace System::Security::Permissions;
|
||||
|
||||
//
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
//
|
||||
[assembly:AssemblyTitleAttribute("FLACDotNet")];
|
||||
[assembly:AssemblyDescriptionAttribute("")];
|
||||
[assembly:AssemblyConfigurationAttribute("")];
|
||||
[assembly:AssemblyCompanyAttribute("")];
|
||||
[assembly:AssemblyProductAttribute("")];
|
||||
[assembly:AssemblyCopyrightAttribute("Copyright 2006-2007 Moitah")];
|
||||
[assembly:AssemblyTrademarkAttribute("")];
|
||||
[assembly:AssemblyCultureAttribute("")];
|
||||
|
||||
//
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the value or you can default the Revision and Build Numbers
|
||||
// by using the '*' as shown below:
|
||||
|
||||
[assembly:AssemblyVersionAttribute("1.5.0.0")];
|
||||
|
||||
[assembly:ComVisible(false)];
|
||||
|
||||
[assembly:CLSCompliantAttribute(true)];
|
||||
|
||||
[assembly:SecurityPermission(SecurityAction::RequestMinimum, UnmanagedCode = true)];
|
||||
36
FLACDotNet/FLACDotNet.sln
Normal file
36
FLACDotNet/FLACDotNet.sln
Normal file
@@ -0,0 +1,36 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 9.00
|
||||
# Visual Studio 2005
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FLACDotNet", "FLACDotNet.vcproj", "{E70FA90A-7012-4A52-86B5-362B699D1540}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "APEDotNet", "..\APEDotNet\APEDotNet.vcproj", "{9AE965C4-301E-4C01-B90F-297AF341ACC6}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Debug|x64 = Debug|x64
|
||||
Release|Win32 = Release|Win32
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{E70FA90A-7012-4A52-86B5-362B699D1540}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{E70FA90A-7012-4A52-86B5-362B699D1540}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{E70FA90A-7012-4A52-86B5-362B699D1540}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{E70FA90A-7012-4A52-86B5-362B699D1540}.Debug|x64.Build.0 = Debug|x64
|
||||
{E70FA90A-7012-4A52-86B5-362B699D1540}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{E70FA90A-7012-4A52-86B5-362B699D1540}.Release|Win32.Build.0 = Release|Win32
|
||||
{E70FA90A-7012-4A52-86B5-362B699D1540}.Release|x64.ActiveCfg = Release|x64
|
||||
{E70FA90A-7012-4A52-86B5-362B699D1540}.Release|x64.Build.0 = Release|x64
|
||||
{9AE965C4-301E-4C01-B90F-297AF341ACC6}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{9AE965C4-301E-4C01-B90F-297AF341ACC6}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{9AE965C4-301E-4C01-B90F-297AF341ACC6}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{9AE965C4-301E-4C01-B90F-297AF341ACC6}.Debug|x64.Build.0 = Debug|x64
|
||||
{9AE965C4-301E-4C01-B90F-297AF341ACC6}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{9AE965C4-301E-4C01-B90F-297AF341ACC6}.Release|Win32.Build.0 = Release|Win32
|
||||
{9AE965C4-301E-4C01-B90F-297AF341ACC6}.Release|x64.ActiveCfg = Release|x64
|
||||
{9AE965C4-301E-4C01-B90F-297AF341ACC6}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
414
FLACDotNet/FLACDotNet.vcproj
Normal file
414
FLACDotNet/FLACDotNet.vcproj
Normal file
@@ -0,0 +1,414 @@
|
||||
<?xml version="1.0" encoding="Windows-1252"?>
|
||||
<VisualStudioProject
|
||||
ProjectType="Visual C++"
|
||||
Version="8,00"
|
||||
Name="FLACDotNet"
|
||||
ProjectGUID="{E70FA90A-7012-4A52-86B5-362B699D1540}"
|
||||
RootNamespace="FLACDotNet"
|
||||
Keyword="ManagedCProj"
|
||||
>
|
||||
<Platforms>
|
||||
<Platform
|
||||
Name="Win32"
|
||||
/>
|
||||
<Platform
|
||||
Name="x64"
|
||||
/>
|
||||
</Platforms>
|
||||
<ToolFiles>
|
||||
</ToolFiles>
|
||||
<Configurations>
|
||||
<Configuration
|
||||
Name="Debug|Win32"
|
||||
OutputDirectory="$(SolutionDir)..\bin\$(PlatformName)\$(ConfigurationName)"
|
||||
IntermediateDirectory="$(SolutionDir)..\obj\$(ProjectName)\$(PlatformName)\$(ConfigurationName)"
|
||||
ConfigurationType="2"
|
||||
CharacterSet="1"
|
||||
ManagedExtensions="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="../flac/include"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CRT_SECURE_NO_WARNINGS"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
AssemblyDebug="1"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Debug|x64"
|
||||
OutputDirectory="$(SolutionDir)..\bin\$(PlatformName)\$(ConfigurationName)"
|
||||
IntermediateDirectory="$(SolutionDir)..\obj\$(ProjectName)\$(PlatformName)\$(ConfigurationName)"
|
||||
ConfigurationType="2"
|
||||
CharacterSet="1"
|
||||
ManagedExtensions="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
TargetEnvironment="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
Optimization="0"
|
||||
AdditionalIncludeDirectories="../flac/include"
|
||||
PreprocessorDefinitions="WIN32;_DEBUG;_CRT_SECURE_NO_WARNINGS"
|
||||
RuntimeLibrary="3"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="2"
|
||||
GenerateDebugInformation="true"
|
||||
AssemblyDebug="1"
|
||||
TargetMachine="17"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|Win32"
|
||||
OutputDirectory="$(SolutionDir)..\bin\$(PlatformName)\$(ConfigurationName)"
|
||||
IntermediateDirectory="$(SolutionDir)..\obj\$(ProjectName)\$(PlatformName)\$(ConfigurationName)"
|
||||
ConfigurationType="2"
|
||||
CharacterSet="1"
|
||||
ManagedExtensions="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalIncludeDirectories="../flac/include"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CRT_SECURE_NO_WARNINGS"
|
||||
RuntimeLibrary="2"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
TargetMachine="1"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
<Configuration
|
||||
Name="Release|x64"
|
||||
OutputDirectory="$(SolutionDir)..\bin\$(PlatformName)\$(ConfigurationName)"
|
||||
IntermediateDirectory="$(SolutionDir)..\obj\$(ProjectName)\$(PlatformName)\$(ConfigurationName)"
|
||||
ConfigurationType="2"
|
||||
CharacterSet="1"
|
||||
ManagedExtensions="1"
|
||||
WholeProgramOptimization="1"
|
||||
>
|
||||
<Tool
|
||||
Name="VCPreBuildEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCustomBuildTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXMLDataGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebServiceProxyGeneratorTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCMIDLTool"
|
||||
TargetEnvironment="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCCLCompilerTool"
|
||||
AdditionalIncludeDirectories="../flac/include"
|
||||
PreprocessorDefinitions="WIN32;NDEBUG;_CRT_SECURE_NO_WARNINGS"
|
||||
RuntimeLibrary="2"
|
||||
UsePrecompiledHeader="0"
|
||||
WarningLevel="3"
|
||||
DebugInformationFormat="3"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManagedResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCResourceCompilerTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPreLinkEventTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
LinkIncremental="1"
|
||||
GenerateDebugInformation="true"
|
||||
TargetMachine="17"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCALinkTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCManifestTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCXDCMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCBscMakeTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCFxCopTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCAppVerifierTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCWebDeploymentTool"
|
||||
/>
|
||||
<Tool
|
||||
Name="VCPostBuildEventTool"
|
||||
/>
|
||||
</Configuration>
|
||||
</Configurations>
|
||||
<References>
|
||||
<AssemblyReference
|
||||
RelativePath="System.dll"
|
||||
AssemblyName="System, Version=2.0.0.0, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL"
|
||||
/>
|
||||
<AssemblyReference
|
||||
RelativePath="System.Data.dll"
|
||||
AssemblyName="System.Data, Version=2.0.0.0, PublicKeyToken=b77a5c561934e089, processorArchitecture=x86"
|
||||
/>
|
||||
<AssemblyReference
|
||||
RelativePath="System.XML.dll"
|
||||
AssemblyName="System.Xml, Version=2.0.0.0, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL"
|
||||
/>
|
||||
</References>
|
||||
<Files>
|
||||
<Filter
|
||||
Name="Source Files"
|
||||
Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\AssemblyInfo.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\FLACDotNet.cpp"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\resource.h"
|
||||
>
|
||||
</File>
|
||||
<Filter
|
||||
Name="FLAC"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\FLAC\all.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\FLAC\assert.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\FLAC\callback.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\FLAC\export.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\FLAC\format.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\FLAC\metadata.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\FLAC\ordinals.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\FLAC\stream_decoder.h"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\FLAC\stream_encoder.h"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
|
||||
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\app.ico"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\app.rc"
|
||||
>
|
||||
</File>
|
||||
</Filter>
|
||||
</Files>
|
||||
<Globals>
|
||||
</Globals>
|
||||
</VisualStudioProject>
|
||||
BIN
FLACDotNet/app.ico
Normal file
BIN
FLACDotNet/app.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
63
FLACDotNet/app.rc
Normal file
63
FLACDotNet/app.rc
Normal file
@@ -0,0 +1,63 @@
|
||||
// Microsoft Visual C++ generated resource script.
|
||||
//
|
||||
#include "resource.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (U.S.) resources
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Icon
|
||||
//
|
||||
|
||||
// Icon placed first or with lowest ID value becomes application icon
|
||||
|
||||
LANGUAGE 9, 1
|
||||
#pragma code_page(1252)
|
||||
1 ICON "app.ico"
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TEXTINCLUDE
|
||||
//
|
||||
|
||||
1 TEXTINCLUDE
|
||||
BEGIN
|
||||
"resource.h\0"
|
||||
"\0"
|
||||
END
|
||||
|
||||
2 TEXTINCLUDE
|
||||
BEGIN
|
||||
"#include ""afxres.h""\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE
|
||||
BEGIN
|
||||
"\0"
|
||||
END
|
||||
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
||||
610
FLACDotNet/cuesheet.c
Normal file
610
FLACDotNet/cuesheet.c
Normal file
@@ -0,0 +1,610 @@
|
||||
/* grabbag - Convenience lib for various routines common to several tools
|
||||
* Copyright (C) 2002,2003,2004,2005,2006,2007 Josh Coalson
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include "FLAC/assert.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
unsigned grabbag__cuesheet_msf_to_frame(unsigned minutes, unsigned seconds, unsigned frames)
|
||||
{
|
||||
return ((minutes * 60) + seconds) * 75 + frames;
|
||||
}
|
||||
|
||||
void grabbag__cuesheet_frame_to_msf(unsigned frame, unsigned *minutes, unsigned *seconds, unsigned *frames)
|
||||
{
|
||||
*frames = frame % 75;
|
||||
frame /= 75;
|
||||
*seconds = frame % 60;
|
||||
frame /= 60;
|
||||
*minutes = frame;
|
||||
}
|
||||
|
||||
/* since we only care about values >= 0 or error, returns < 0 for any illegal string, else value */
|
||||
static int local__parse_int_(const char *s)
|
||||
{
|
||||
int ret = 0;
|
||||
char c;
|
||||
|
||||
if(*s == '\0')
|
||||
return -1;
|
||||
|
||||
while('\0' != (c = *s++))
|
||||
if(c >= '0' && c <= '9')
|
||||
ret = ret * 10 + (c - '0');
|
||||
else
|
||||
return -1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* since we only care about values >= 0 or error, returns < 0 for any illegal string, else value */
|
||||
static FLAC__int64 local__parse_int64_(const char *s)
|
||||
{
|
||||
FLAC__int64 ret = 0;
|
||||
char c;
|
||||
|
||||
if(*s == '\0')
|
||||
return -1;
|
||||
|
||||
while('\0' != (c = *s++))
|
||||
if(c >= '0' && c <= '9')
|
||||
ret = ret * 10 + (c - '0');
|
||||
else
|
||||
return -1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* accept '[0-9]+:[0-9][0-9]?:[0-9][0-9]?', but max second of 59 and max frame of 74, e.g. 0:0:0, 123:45:67
|
||||
* return sample number or <0 for error
|
||||
*/
|
||||
static FLAC__int64 local__parse_msf_(const char *s)
|
||||
{
|
||||
FLAC__int64 ret, field;
|
||||
char c;
|
||||
|
||||
c = *s++;
|
||||
if(c >= '0' && c <= '9')
|
||||
field = (c - '0');
|
||||
else
|
||||
return -1;
|
||||
while(':' != (c = *s++)) {
|
||||
if(c >= '0' && c <= '9')
|
||||
field = field * 10 + (c - '0');
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = field * 60 * 44100;
|
||||
|
||||
c = *s++;
|
||||
if(c >= '0' && c <= '9')
|
||||
field = (c - '0');
|
||||
else
|
||||
return -1;
|
||||
if(':' != (c = *s++)) {
|
||||
if(c >= '0' && c <= '9') {
|
||||
field = field * 10 + (c - '0');
|
||||
c = *s++;
|
||||
if(c != ':')
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(field >= 60)
|
||||
return -1;
|
||||
|
||||
ret += field * 44100;
|
||||
|
||||
c = *s++;
|
||||
if(c >= '0' && c <= '9')
|
||||
field = (c - '0');
|
||||
else
|
||||
return -1;
|
||||
if('\0' != (c = *s++)) {
|
||||
if(c >= '0' && c <= '9') {
|
||||
field = field * 10 + (c - '0');
|
||||
c = *s++;
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(c != '\0')
|
||||
return -1;
|
||||
|
||||
if(field >= 75)
|
||||
return -1;
|
||||
|
||||
ret += field * (44100 / 75);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static char *local__get_field_(char **s, FLAC__bool allow_quotes)
|
||||
{
|
||||
FLAC__bool has_quote = false;
|
||||
char *p;
|
||||
|
||||
FLAC__ASSERT(0 != s);
|
||||
|
||||
if(0 == *s)
|
||||
return 0;
|
||||
|
||||
/* skip leading whitespace */
|
||||
while(**s && 0 != strchr(" \t\r\n", **s))
|
||||
(*s)++;
|
||||
|
||||
if(**s == 0) {
|
||||
*s = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(allow_quotes && (**s == '"')) {
|
||||
has_quote = true;
|
||||
(*s)++;
|
||||
if(**s == 0) {
|
||||
*s = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
p = *s;
|
||||
|
||||
if(has_quote) {
|
||||
*s = strchr(*s, '\"');
|
||||
/* if there is no matching end quote, it's an error */
|
||||
if(0 == *s)
|
||||
p = *s = 0;
|
||||
else {
|
||||
**s = '\0';
|
||||
(*s)++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
while(**s && 0 == strchr(" \t\r\n", **s))
|
||||
(*s)++;
|
||||
if(**s) {
|
||||
**s = '\0';
|
||||
(*s)++;
|
||||
}
|
||||
else
|
||||
*s = 0;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
static FLAC__bool local__cuesheet_parse_(FILE *file, const char **error_message, unsigned *last_line_read, FLAC__StreamMetadata *cuesheet, FLAC__bool is_cdda, FLAC__uint64 lead_out_offset)
|
||||
{
|
||||
#if defined _MSC_VER || defined __MINGW32__ || defined __EMX__
|
||||
#define FLAC__STRCASECMP stricmp
|
||||
#else
|
||||
#define FLAC__STRCASECMP strcasecmp
|
||||
#endif
|
||||
char buffer[4096], *line, *field;
|
||||
unsigned forced_leadout_track_num = 0;
|
||||
FLAC__uint64 forced_leadout_track_offset = 0;
|
||||
int in_track_num = -1, in_index_num = -1;
|
||||
FLAC__bool disc_has_catalog = false, track_has_flags = false, track_has_isrc = false, has_forced_leadout = false;
|
||||
FLAC__StreamMetadata_CueSheet *cs = &cuesheet->data.cue_sheet;
|
||||
|
||||
cs->lead_in = is_cdda? 2 * 44100 /* The default lead-in size for CD-DA */ : 0;
|
||||
cs->is_cd = is_cdda;
|
||||
|
||||
while(0 != fgets(buffer, sizeof(buffer), file)) {
|
||||
(*last_line_read)++;
|
||||
line = buffer;
|
||||
|
||||
{
|
||||
size_t linelen = strlen(line);
|
||||
if((linelen == sizeof(buffer)-1) && line[linelen-1] != '\n') {
|
||||
*error_message = "line too long";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(0 != (field = local__get_field_(&line, /*allow_quotes=*/false))) {
|
||||
if(0 == FLAC__STRCASECMP(field, "CATALOG")) {
|
||||
if(disc_has_catalog) {
|
||||
*error_message = "found multiple CATALOG commands";
|
||||
return false;
|
||||
}
|
||||
if(0 == (field = local__get_field_(&line, /*allow_quotes=*/true))) {
|
||||
*error_message = "CATALOG is missing catalog number";
|
||||
return false;
|
||||
}
|
||||
if(strlen(field) >= sizeof(cs->media_catalog_number)) {
|
||||
*error_message = "CATALOG number is too long";
|
||||
return false;
|
||||
}
|
||||
if(is_cdda && (strlen(field) != 13 || strspn(field, "0123456789") != 13)) {
|
||||
*error_message = "CD-DA CATALOG number must be 13 decimal digits";
|
||||
return false;
|
||||
}
|
||||
strcpy(cs->media_catalog_number, field);
|
||||
disc_has_catalog = true;
|
||||
}
|
||||
else if(0 == FLAC__STRCASECMP(field, "FLAGS")) {
|
||||
if(track_has_flags) {
|
||||
*error_message = "found multiple FLAGS commands";
|
||||
return false;
|
||||
}
|
||||
if(in_track_num < 0 || in_index_num >= 0) {
|
||||
*error_message = "FLAGS command must come after TRACK but before INDEX";
|
||||
return false;
|
||||
}
|
||||
while(0 != (field = local__get_field_(&line, /*allow_quotes=*/false))) {
|
||||
if(0 == FLAC__STRCASECMP(field, "PRE"))
|
||||
cs->tracks[cs->num_tracks-1].pre_emphasis = 1;
|
||||
}
|
||||
track_has_flags = true;
|
||||
}
|
||||
else if(0 == FLAC__STRCASECMP(field, "INDEX")) {
|
||||
FLAC__int64 xx;
|
||||
FLAC__StreamMetadata_CueSheet_Track *track = &cs->tracks[cs->num_tracks-1];
|
||||
if(in_track_num < 0) {
|
||||
*error_message = "found INDEX before any TRACK";
|
||||
return false;
|
||||
}
|
||||
if(0 == (field = local__get_field_(&line, /*allow_quotes=*/false))) {
|
||||
*error_message = "INDEX is missing index number";
|
||||
return false;
|
||||
}
|
||||
in_index_num = local__parse_int_(field);
|
||||
if(in_index_num < 0) {
|
||||
*error_message = "INDEX has invalid index number";
|
||||
return false;
|
||||
}
|
||||
FLAC__ASSERT(cs->num_tracks > 0);
|
||||
if(track->num_indices == 0) {
|
||||
/* it's the first index point of the track */
|
||||
if(in_index_num > 1) {
|
||||
*error_message = "first INDEX number of a TRACK must be 0 or 1";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(in_index_num != track->indices[track->num_indices-1].number + 1) {
|
||||
*error_message = "INDEX numbers must be sequential";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(is_cdda && in_index_num > 99) {
|
||||
*error_message = "CD-DA INDEX number must be between 0 and 99, inclusive";
|
||||
return false;
|
||||
}
|
||||
/*@@@ search for duplicate track number? */
|
||||
if(0 == (field = local__get_field_(&line, /*allow_quotes=*/false))) {
|
||||
*error_message = "INDEX is missing an offset after the index number";
|
||||
return false;
|
||||
}
|
||||
xx = local__parse_msf_(field);
|
||||
if(xx < 0) {
|
||||
if(is_cdda) {
|
||||
*error_message = "illegal INDEX offset (not of the form MM:SS:FF)";
|
||||
return false;
|
||||
}
|
||||
xx = local__parse_int64_(field);
|
||||
if(xx < 0) {
|
||||
*error_message = "illegal INDEX offset";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(is_cdda && cs->num_tracks == 1 && cs->tracks[0].num_indices == 0 && xx != 0) {
|
||||
*error_message = "first INDEX of first TRACK must have an offset of 00:00:00";
|
||||
return false;
|
||||
}
|
||||
if(is_cdda && track->num_indices > 0 && (FLAC__uint64)xx <= track->indices[track->num_indices-1].offset) {
|
||||
*error_message = "CD-DA INDEX offsets must increase in time";
|
||||
return false;
|
||||
}
|
||||
/* fill in track offset if it's the first index of the track */
|
||||
if(track->num_indices == 0)
|
||||
track->offset = (FLAC__uint64)xx;
|
||||
if(is_cdda && cs->num_tracks > 1) {
|
||||
const FLAC__StreamMetadata_CueSheet_Track *prev = &cs->tracks[cs->num_tracks-2];
|
||||
if((FLAC__uint64)xx <= prev->offset + prev->indices[prev->num_indices-1].offset) {
|
||||
*error_message = "CD-DA INDEX offsets must increase in time";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(!FLAC__metadata_object_cuesheet_track_insert_blank_index(cuesheet, cs->num_tracks-1, track->num_indices)) {
|
||||
*error_message = "memory allocation error";
|
||||
return false;
|
||||
}
|
||||
track->indices[track->num_indices-1].offset = (FLAC__uint64)xx - track->offset;
|
||||
track->indices[track->num_indices-1].number = in_index_num;
|
||||
}
|
||||
else if(0 == FLAC__STRCASECMP(field, "ISRC")) {
|
||||
char *l, *r;
|
||||
if(track_has_isrc) {
|
||||
*error_message = "found multiple ISRC commands";
|
||||
return false;
|
||||
}
|
||||
if(in_track_num < 0 || in_index_num >= 0) {
|
||||
*error_message = "ISRC command must come after TRACK but before INDEX";
|
||||
return false;
|
||||
}
|
||||
if(0 == (field = local__get_field_(&line, /*allow_quotes=*/false))) {
|
||||
*error_message = "ISRC is missing ISRC number";
|
||||
return false;
|
||||
}
|
||||
/* strip out dashes */
|
||||
for(l = r = field; *r; r++) {
|
||||
if(*r != '-')
|
||||
*l++ = *r;
|
||||
}
|
||||
*l = '\0';
|
||||
if(strlen(field) != 12 || strspn(field, "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") < 5 || strspn(field+5, "1234567890") != 7) {
|
||||
*error_message = "invalid ISRC number";
|
||||
return false;
|
||||
}
|
||||
strcpy(cs->tracks[cs->num_tracks-1].isrc, field);
|
||||
track_has_isrc = true;
|
||||
}
|
||||
else if(0 == FLAC__STRCASECMP(field, "TRACK")) {
|
||||
if(cs->num_tracks > 0) {
|
||||
const FLAC__StreamMetadata_CueSheet_Track *prev = &cs->tracks[cs->num_tracks-1];
|
||||
if(
|
||||
prev->num_indices == 0 ||
|
||||
(
|
||||
is_cdda &&
|
||||
(
|
||||
(prev->num_indices == 1 && prev->indices[0].number != 1) ||
|
||||
(prev->num_indices == 2 && prev->indices[0].number != 1 && prev->indices[1].number != 1)
|
||||
)
|
||||
)
|
||||
) {
|
||||
*error_message = is_cdda?
|
||||
"previous TRACK must specify at least one INDEX 01" :
|
||||
"previous TRACK must specify at least one INDEX";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(0 == (field = local__get_field_(&line, /*allow_quotes=*/false))) {
|
||||
*error_message = "TRACK is missing track number";
|
||||
return false;
|
||||
}
|
||||
in_track_num = local__parse_int_(field);
|
||||
if(in_track_num < 0) {
|
||||
*error_message = "TRACK has invalid track number";
|
||||
return false;
|
||||
}
|
||||
if(in_track_num == 0) {
|
||||
*error_message = "TRACK number must be greater than 0";
|
||||
return false;
|
||||
}
|
||||
if(is_cdda) {
|
||||
if(in_track_num > 99) {
|
||||
*error_message = "CD-DA TRACK number must be between 1 and 99, inclusive";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(in_track_num == 255) {
|
||||
*error_message = "TRACK number 255 is reserved for the lead-out";
|
||||
return false;
|
||||
}
|
||||
else if(in_track_num > 255) {
|
||||
*error_message = "TRACK number must be between 1 and 254, inclusive";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(is_cdda && cs->num_tracks > 0 && in_track_num != cs->tracks[cs->num_tracks-1].number + 1) {
|
||||
*error_message = "CD-DA TRACK numbers must be sequential";
|
||||
return false;
|
||||
}
|
||||
/*@@@ search for duplicate track number? */
|
||||
if(0 == (field = local__get_field_(&line, /*allow_quotes=*/false))) {
|
||||
*error_message = "TRACK is missing a track type after the track number";
|
||||
return false;
|
||||
}
|
||||
if(!FLAC__metadata_object_cuesheet_insert_blank_track(cuesheet, cs->num_tracks)) {
|
||||
*error_message = "memory allocation error";
|
||||
return false;
|
||||
}
|
||||
cs->tracks[cs->num_tracks-1].number = in_track_num;
|
||||
cs->tracks[cs->num_tracks-1].type = (0 == FLAC__STRCASECMP(field, "AUDIO"))? 0 : 1; /*@@@ should we be more strict with the value here? */
|
||||
in_index_num = -1;
|
||||
track_has_flags = false;
|
||||
track_has_isrc = false;
|
||||
}
|
||||
else if(0 == FLAC__STRCASECMP(field, "REM")) {
|
||||
if(0 != (field = local__get_field_(&line, /*allow_quotes=*/false))) {
|
||||
if(0 == strcmp(field, "FLAC__lead-in")) {
|
||||
FLAC__int64 xx;
|
||||
if(0 == (field = local__get_field_(&line, /*allow_quotes=*/false))) {
|
||||
*error_message = "FLAC__lead-in is missing offset";
|
||||
return false;
|
||||
}
|
||||
xx = local__parse_int64_(field);
|
||||
if(xx < 0) {
|
||||
*error_message = "illegal FLAC__lead-in offset";
|
||||
return false;
|
||||
}
|
||||
if(is_cdda && xx % 588 != 0) {
|
||||
*error_message = "illegal CD-DA FLAC__lead-in offset, must be even multiple of 588 samples";
|
||||
return false;
|
||||
}
|
||||
cs->lead_in = (FLAC__uint64)xx;
|
||||
}
|
||||
else if(0 == strcmp(field, "FLAC__lead-out")) {
|
||||
int track_num;
|
||||
FLAC__int64 offset;
|
||||
if(has_forced_leadout) {
|
||||
*error_message = "multiple FLAC__lead-out commands";
|
||||
return false;
|
||||
}
|
||||
if(0 == (field = local__get_field_(&line, /*allow_quotes=*/false))) {
|
||||
*error_message = "FLAC__lead-out is missing track number";
|
||||
return false;
|
||||
}
|
||||
track_num = local__parse_int_(field);
|
||||
if(track_num < 0) {
|
||||
*error_message = "illegal FLAC__lead-out track number";
|
||||
return false;
|
||||
}
|
||||
forced_leadout_track_num = (unsigned)track_num;
|
||||
/*@@@ search for duplicate track number? */
|
||||
if(0 == (field = local__get_field_(&line, /*allow_quotes=*/false))) {
|
||||
*error_message = "FLAC__lead-out is missing offset";
|
||||
return false;
|
||||
}
|
||||
offset = local__parse_int64_(field);
|
||||
if(offset < 0) {
|
||||
*error_message = "illegal FLAC__lead-out offset";
|
||||
return false;
|
||||
}
|
||||
forced_leadout_track_offset = (FLAC__uint64)offset;
|
||||
if(forced_leadout_track_offset != lead_out_offset) {
|
||||
*error_message = "FLAC__lead-out offset does not match end-of-stream offset";
|
||||
return false;
|
||||
}
|
||||
has_forced_leadout = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(cs->num_tracks == 0) {
|
||||
*error_message = "there must be at least one TRACK command";
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
const FLAC__StreamMetadata_CueSheet_Track *prev = &cs->tracks[cs->num_tracks-1];
|
||||
if(
|
||||
prev->num_indices == 0 ||
|
||||
(
|
||||
is_cdda &&
|
||||
(
|
||||
(prev->num_indices == 1 && prev->indices[0].number != 1) ||
|
||||
(prev->num_indices == 2 && prev->indices[0].number != 1 && prev->indices[1].number != 1)
|
||||
)
|
||||
)
|
||||
) {
|
||||
*error_message = is_cdda?
|
||||
"previous TRACK must specify at least one INDEX 01" :
|
||||
"previous TRACK must specify at least one INDEX";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(!has_forced_leadout) {
|
||||
forced_leadout_track_num = is_cdda? 170 : 255;
|
||||
forced_leadout_track_offset = lead_out_offset;
|
||||
}
|
||||
if(!FLAC__metadata_object_cuesheet_insert_blank_track(cuesheet, cs->num_tracks)) {
|
||||
*error_message = "memory allocation error";
|
||||
return false;
|
||||
}
|
||||
cs->tracks[cs->num_tracks-1].number = forced_leadout_track_num;
|
||||
cs->tracks[cs->num_tracks-1].offset = forced_leadout_track_offset;
|
||||
|
||||
if(!feof(file)) {
|
||||
*error_message = "read error";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
#undef FLAC__STRCASECMP
|
||||
}
|
||||
|
||||
FLAC__StreamMetadata *grabbag__cuesheet_parse(FILE *file, const char **error_message, unsigned *last_line_read, FLAC__bool is_cdda, FLAC__uint64 lead_out_offset)
|
||||
{
|
||||
FLAC__StreamMetadata *cuesheet;
|
||||
|
||||
FLAC__ASSERT(0 != file);
|
||||
FLAC__ASSERT(0 != error_message);
|
||||
FLAC__ASSERT(0 != last_line_read);
|
||||
|
||||
*last_line_read = 0;
|
||||
cuesheet = FLAC__metadata_object_new(FLAC__METADATA_TYPE_CUESHEET);
|
||||
|
||||
if(0 == cuesheet) {
|
||||
*error_message = "memory allocation error";
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!local__cuesheet_parse_(file, error_message, last_line_read, cuesheet, is_cdda, lead_out_offset)) {
|
||||
FLAC__metadata_object_delete(cuesheet);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return cuesheet;
|
||||
}
|
||||
|
||||
void grabbag__cuesheet_emit(FILE *file, const FLAC__StreamMetadata *cuesheet, const char *file_reference)
|
||||
{
|
||||
const FLAC__StreamMetadata_CueSheet *cs;
|
||||
unsigned track_num, index_num;
|
||||
|
||||
FLAC__ASSERT(0 != file);
|
||||
FLAC__ASSERT(0 != cuesheet);
|
||||
FLAC__ASSERT(cuesheet->type == FLAC__METADATA_TYPE_CUESHEET);
|
||||
|
||||
cs = &cuesheet->data.cue_sheet;
|
||||
|
||||
if(*(cs->media_catalog_number))
|
||||
fprintf(file, "CATALOG %s\n", cs->media_catalog_number);
|
||||
fprintf(file, "FILE %s\n", file_reference);
|
||||
|
||||
for(track_num = 0; track_num < cs->num_tracks-1; track_num++) {
|
||||
const FLAC__StreamMetadata_CueSheet_Track *track = cs->tracks + track_num;
|
||||
|
||||
fprintf(file, " TRACK %02u %s\n", (unsigned)track->number, track->type == 0? "AUDIO" : "DATA");
|
||||
|
||||
if(track->pre_emphasis)
|
||||
fprintf(file, " FLAGS PRE\n");
|
||||
if(*(track->isrc))
|
||||
fprintf(file, " ISRC %s\n", track->isrc);
|
||||
|
||||
for(index_num = 0; index_num < track->num_indices; index_num++) {
|
||||
const FLAC__StreamMetadata_CueSheet_Index *index = track->indices + index_num;
|
||||
|
||||
fprintf(file, " INDEX %02u ", (unsigned)index->number);
|
||||
if(cs->is_cd) {
|
||||
const unsigned logical_frame = (unsigned)((track->offset + index->offset) / (44100 / 75));
|
||||
unsigned m, s, f;
|
||||
grabbag__cuesheet_frame_to_msf(logical_frame, &m, &s, &f);
|
||||
fprintf(file, "%02u:%02u:%02u\n", m, s, f);
|
||||
}
|
||||
else
|
||||
#ifdef _MSC_VER
|
||||
fprintf(file, "%I64u\n", track->offset + index->offset);
|
||||
#else
|
||||
fprintf(file, "%llu\n", (unsigned long long)(track->offset + index->offset));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
fprintf(file, "REM FLAC__lead-in %I64u\n", cs->lead_in);
|
||||
fprintf(file, "REM FLAC__lead-out %u %I64u\n", (unsigned)cs->tracks[track_num].number, cs->tracks[track_num].offset);
|
||||
#else
|
||||
fprintf(file, "REM FLAC__lead-in %llu\n", (unsigned long long)cs->lead_in);
|
||||
fprintf(file, "REM FLAC__lead-out %u %llu\n", (unsigned)cs->tracks[track_num].number, (unsigned long long)cs->tracks[track_num].offset);
|
||||
#endif
|
||||
}
|
||||
547
FLACDotNet/flacdotnet.cpp
Normal file
547
FLACDotNet/flacdotnet.cpp
Normal file
@@ -0,0 +1,547 @@
|
||||
// ****************************************************************************
|
||||
//
|
||||
// Copyright (c) 2006-2007 Moitah (moitah@yahoo.com)
|
||||
// All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright notice,
|
||||
// this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above copyright
|
||||
// notice, this list of conditions and the following disclaimer in the
|
||||
// documentation and/or other materials provided with the distribution.
|
||||
// * Neither the name of the author nor the names of its contributors may be
|
||||
// used to endorse or promote products derived from this software without
|
||||
// specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
// POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// ****************************************************************************
|
||||
|
||||
using namespace System;
|
||||
using namespace System::Text;
|
||||
using namespace System::Collections::Generic;
|
||||
using namespace System::Collections::Specialized;
|
||||
using namespace System::Runtime::InteropServices;
|
||||
|
||||
#include "FLAC\all.h"
|
||||
#include <string>
|
||||
|
||||
struct FLAC__Metadata_Iterator
|
||||
{
|
||||
int dummy;
|
||||
};
|
||||
|
||||
struct FLAC__Metadata_Chain
|
||||
{
|
||||
int dummy;
|
||||
};
|
||||
|
||||
namespace FLACDotNet {
|
||||
[UnmanagedFunctionPointer(CallingConvention::Cdecl)]
|
||||
public delegate FLAC__StreamDecoderWriteStatus DecoderWriteDelegate(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data);
|
||||
[UnmanagedFunctionPointer(CallingConvention::Cdecl)]
|
||||
public delegate void DecoderMetadataDelegate(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data);
|
||||
[UnmanagedFunctionPointer(CallingConvention::Cdecl)]
|
||||
public delegate void DecoderErrorDelegate(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data);
|
||||
|
||||
public ref class FLACReader {
|
||||
public:
|
||||
FLACReader(String^ path) {
|
||||
IntPtr pathChars;
|
||||
FILE *hFile;
|
||||
_tags = gcnew NameValueCollection();
|
||||
|
||||
_writeDel = gcnew DecoderWriteDelegate(this, &FLACReader::WriteCallback);
|
||||
_metadataDel = gcnew DecoderMetadataDelegate(this, &FLACReader::MetadataCallback);
|
||||
_errorDel = gcnew DecoderErrorDelegate(this, &FLACReader::ErrorCallback);
|
||||
|
||||
_decoderActive = false;
|
||||
|
||||
_sampleOffset = 0;
|
||||
_samplesWaiting = false;
|
||||
_sampleBuffer = nullptr;
|
||||
_path = path;
|
||||
|
||||
pathChars = Marshal::StringToHGlobalUni(_path);
|
||||
hFile = _wfopen ((const wchar_t*)pathChars.ToPointer(), L"rb");
|
||||
Marshal::FreeHGlobal(pathChars);
|
||||
if (!hFile) {
|
||||
throw gcnew Exception("Unable to open file.");
|
||||
}
|
||||
|
||||
_decoder = FLAC__stream_decoder_new();
|
||||
|
||||
if (!FLAC__stream_decoder_set_metadata_respond (_decoder, FLAC__METADATA_TYPE_VORBIS_COMMENT))
|
||||
throw gcnew Exception("Unable to setup the decoder.");
|
||||
|
||||
if (FLAC__stream_decoder_init_FILE(_decoder, hFile,
|
||||
(FLAC__StreamDecoderWriteCallback)Marshal::GetFunctionPointerForDelegate(_writeDel).ToPointer(),
|
||||
(FLAC__StreamDecoderMetadataCallback)Marshal::GetFunctionPointerForDelegate(_metadataDel).ToPointer(),
|
||||
(FLAC__StreamDecoderErrorCallback)Marshal::GetFunctionPointerForDelegate(_errorDel).ToPointer(),
|
||||
NULL) != FLAC__STREAM_DECODER_INIT_STATUS_OK)
|
||||
{
|
||||
throw gcnew Exception("Unable to initialize the decoder.");
|
||||
}
|
||||
|
||||
_decoderActive = true;
|
||||
|
||||
if (!FLAC__stream_decoder_process_until_end_of_metadata(_decoder)) {
|
||||
throw gcnew Exception("Unable to retrieve metadata.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
~FLACReader ()
|
||||
{
|
||||
Close ();
|
||||
}
|
||||
|
||||
property Int32 BitsPerSample {
|
||||
Int32 get() {
|
||||
return _bitsPerSample;
|
||||
}
|
||||
}
|
||||
|
||||
property Int32 ChannelCount {
|
||||
Int32 get() {
|
||||
return _channelCount;
|
||||
}
|
||||
}
|
||||
|
||||
property Int32 SampleRate {
|
||||
Int32 get() {
|
||||
return _sampleRate;
|
||||
}
|
||||
}
|
||||
|
||||
property Int64 Length {
|
||||
Int64 get() {
|
||||
return _sampleCount;
|
||||
}
|
||||
}
|
||||
|
||||
property Int64 Position {
|
||||
Int64 get() {
|
||||
return _sampleOffset;
|
||||
}
|
||||
void set(Int64 offset) {
|
||||
_sampleOffset = offset;
|
||||
_samplesWaiting = false;
|
||||
if (!FLAC__stream_decoder_seek_absolute(_decoder, offset)) {
|
||||
throw gcnew Exception("Unable to seek.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
property NameValueCollection^ Tags {
|
||||
NameValueCollection^ get () {
|
||||
return _tags;
|
||||
}
|
||||
void set (NameValueCollection ^tags) {
|
||||
_tags = tags;
|
||||
}
|
||||
}
|
||||
|
||||
bool UpdateTags ()
|
||||
{
|
||||
Close ();
|
||||
|
||||
FLAC__Metadata_Chain* chain = FLAC__metadata_chain_new ();
|
||||
if (!chain) return false;
|
||||
|
||||
IntPtr pathChars = Marshal::StringToHGlobalAnsi(_path);
|
||||
int res = FLAC__metadata_chain_read (chain, (const char*)pathChars.ToPointer());
|
||||
Marshal::FreeHGlobal(pathChars);
|
||||
if (!res) {
|
||||
FLAC__metadata_chain_delete (chain);
|
||||
return false;
|
||||
}
|
||||
FLAC__Metadata_Iterator* i = FLAC__metadata_iterator_new ();
|
||||
FLAC__metadata_iterator_init (i, chain);
|
||||
do {
|
||||
FLAC__StreamMetadata* metadata = FLAC__metadata_iterator_get_block (i);
|
||||
if (metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT)
|
||||
FLAC__metadata_iterator_delete_block (i, false);
|
||||
} while (FLAC__metadata_iterator_next (i));
|
||||
|
||||
FLAC__StreamMetadata * vorbiscomment = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT);
|
||||
for (int tagno = 0; tagno <_tags->Count; tagno++)
|
||||
{
|
||||
String ^ tag_name = _tags->GetKey(tagno);
|
||||
int tag_len = tag_name->Length;
|
||||
char * tag = new char [tag_len + 1];
|
||||
IntPtr nameChars = Marshal::StringToHGlobalAnsi(tag_name);
|
||||
memcpy (tag, (const char*)nameChars.ToPointer(), tag_len);
|
||||
Marshal::FreeHGlobal(nameChars);
|
||||
tag[tag_len] = 0;
|
||||
|
||||
array<String^>^ tag_values = _tags->GetValues(tagno);
|
||||
for (int valno = 0; valno < tag_values->Length; valno++)
|
||||
{
|
||||
UTF8Encoding^ enc = gcnew UTF8Encoding();
|
||||
array<Byte>^ value_array = enc->GetBytes (tag_values[valno]);
|
||||
int value_len = value_array->Length;
|
||||
char * value = new char [value_len + 1];
|
||||
Marshal::Copy (value_array, 0, (IntPtr) value, value_len);
|
||||
value[value_len] = 0;
|
||||
|
||||
FLAC__StreamMetadata_VorbisComment_Entry entry;
|
||||
/* create and entry and append it */
|
||||
if(!FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, tag, value)) {
|
||||
throw gcnew Exception("Unable to add tags, must be valid utf8.");
|
||||
}
|
||||
if(!FLAC__metadata_object_vorbiscomment_append_comment(vorbiscomment, entry, /*copy=*/false)) {
|
||||
throw gcnew Exception("Unable to add tags.");
|
||||
}
|
||||
delete [] value;
|
||||
}
|
||||
delete [] tag;
|
||||
}
|
||||
|
||||
FLAC__metadata_iterator_insert_block_after (i, vorbiscomment);
|
||||
FLAC__metadata_iterator_delete (i);
|
||||
FLAC__metadata_chain_sort_padding (chain);
|
||||
res = FLAC__metadata_chain_write (chain, true, false);
|
||||
FLAC__metadata_chain_delete (chain);
|
||||
return 0 != res;
|
||||
}
|
||||
|
||||
property Int64 Remaining {
|
||||
Int64 get() {
|
||||
return _sampleCount - _sampleOffset;
|
||||
}
|
||||
}
|
||||
|
||||
void Close() {
|
||||
if (!_decoderActive) return;
|
||||
FLAC__stream_decoder_finish(_decoder);
|
||||
FLAC__stream_decoder_delete(_decoder);
|
||||
_decoderActive = false;
|
||||
}
|
||||
|
||||
Int32 Read([Out] array<Int32, 2>^% sampleBuffer) {
|
||||
int sampleCount;
|
||||
|
||||
while (!_samplesWaiting) {
|
||||
if (!FLAC__stream_decoder_process_single(_decoder)) {
|
||||
throw gcnew Exception("An error occurred while decoding.");
|
||||
}
|
||||
}
|
||||
|
||||
sampleCount = _sampleBuffer->GetLength(0);
|
||||
sampleBuffer = _sampleBuffer;
|
||||
_sampleOffset += sampleCount;
|
||||
_samplesWaiting = false;
|
||||
|
||||
return sampleCount;
|
||||
}
|
||||
|
||||
private:
|
||||
DecoderWriteDelegate^ _writeDel;
|
||||
DecoderMetadataDelegate^ _metadataDel;
|
||||
DecoderErrorDelegate^ _errorDel;
|
||||
FLAC__StreamDecoder *_decoder;
|
||||
Int64 _sampleCount, _sampleOffset;
|
||||
Int32 _bitsPerSample, _channelCount, _sampleRate;
|
||||
array<Int32, 2>^ _sampleBuffer;
|
||||
bool _samplesWaiting;
|
||||
NameValueCollection^ _tags;
|
||||
String^ _path;
|
||||
bool _decoderActive;
|
||||
|
||||
FLAC__StreamDecoderWriteStatus WriteCallback(const FLAC__StreamDecoder *decoder,
|
||||
const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data)
|
||||
{
|
||||
Int32 sampleCount = frame->header.blocksize;
|
||||
|
||||
if (_samplesWaiting) {
|
||||
throw gcnew Exception("Received unrequested samples.");
|
||||
}
|
||||
|
||||
if ((frame->header.bits_per_sample != _bitsPerSample) ||
|
||||
(frame->header.channels != _channelCount) ||
|
||||
(frame->header.sample_rate != _sampleRate))
|
||||
{
|
||||
throw gcnew Exception("Format changes within a file are not allowed.");
|
||||
}
|
||||
|
||||
if ((_sampleBuffer == nullptr) || (_sampleBuffer->GetLength(0) != sampleCount)) {
|
||||
_sampleBuffer = gcnew array<Int32, 2>(sampleCount, _channelCount);
|
||||
}
|
||||
|
||||
for (Int32 iChan = 0; iChan < _channelCount; iChan++) {
|
||||
interior_ptr<Int32> pMyBuffer = &_sampleBuffer[0, iChan];
|
||||
const FLAC__int32 *pFLACBuffer = buffer[iChan];
|
||||
const FLAC__int32 *pFLACBufferEnd = pFLACBuffer + sampleCount;
|
||||
|
||||
while (pFLACBuffer < pFLACBufferEnd) {
|
||||
*pMyBuffer = *pFLACBuffer;
|
||||
pMyBuffer += _channelCount;
|
||||
pFLACBuffer++;
|
||||
}
|
||||
}
|
||||
|
||||
_samplesWaiting = true;
|
||||
|
||||
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
|
||||
}
|
||||
|
||||
void MetadataCallback(const FLAC__StreamDecoder *decoder,
|
||||
const FLAC__StreamMetadata *metadata, void *client_data)
|
||||
{
|
||||
if (metadata->type == FLAC__METADATA_TYPE_STREAMINFO)
|
||||
{
|
||||
_bitsPerSample = metadata->data.stream_info.bits_per_sample;
|
||||
_channelCount = metadata->data.stream_info.channels;
|
||||
_sampleRate = metadata->data.stream_info.sample_rate;
|
||||
_sampleCount = metadata->data.stream_info.total_samples;
|
||||
}
|
||||
if (metadata->type == FLAC__METADATA_TYPE_VORBIS_COMMENT)
|
||||
{
|
||||
for (unsigned tagno = 0; tagno < metadata->data.vorbis_comment.num_comments; tagno ++)
|
||||
{
|
||||
char * field_name, * field_value;
|
||||
if(!FLAC__metadata_object_vorbiscomment_entry_to_name_value_pair(metadata->data.vorbis_comment.comments[tagno], &field_name, &field_value))
|
||||
throw gcnew Exception("Unable to parse vorbis comment.");
|
||||
String^ name = Marshal::PtrToStringAnsi ((IntPtr) field_name);
|
||||
free (field_name);
|
||||
array<Byte>^ bvalue = gcnew array<Byte>((int) strlen (field_value));
|
||||
Marshal::Copy ((IntPtr) field_value, bvalue, 0, (int) strlen (field_value));
|
||||
free (field_value);
|
||||
UTF8Encoding^ enc = gcnew UTF8Encoding();
|
||||
String ^value = enc->GetString (bvalue);
|
||||
_tags->Add (name, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ErrorCallback(const FLAC__StreamDecoder *decoder,
|
||||
FLAC__StreamDecoderErrorStatus status, void *client_data)
|
||||
{
|
||||
switch (status) {
|
||||
case FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC:
|
||||
throw gcnew Exception("Synchronization was lost.");
|
||||
case FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER:
|
||||
throw gcnew Exception("Encountered a corrupted frame header.");
|
||||
case FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH:
|
||||
throw gcnew Exception("Frame CRC mismatch.");
|
||||
default:
|
||||
throw gcnew Exception("An unknown error has occurred.");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public ref class FLACWriter {
|
||||
public:
|
||||
FLACWriter(String^ path, Int32 bitsPerSample, Int32 channelCount, Int32 sampleRate) {
|
||||
_initialized = false;
|
||||
_path = path;
|
||||
_finalSampleCount = 0;
|
||||
_samplesWritten = 0;
|
||||
_bitsPerSample = bitsPerSample;
|
||||
_channelCount = channelCount;
|
||||
_sampleRate = sampleRate;
|
||||
_compressionLevel = 5;
|
||||
_paddingLength = 8192;
|
||||
_verify = false;
|
||||
_tags = gcnew NameValueCollection();
|
||||
|
||||
_encoder = FLAC__stream_encoder_new();
|
||||
|
||||
FLAC__stream_encoder_set_bits_per_sample(_encoder, bitsPerSample);
|
||||
FLAC__stream_encoder_set_channels(_encoder, channelCount);
|
||||
FLAC__stream_encoder_set_sample_rate(_encoder, sampleRate);
|
||||
}
|
||||
|
||||
void Close() {
|
||||
FLAC__stream_encoder_finish(_encoder);
|
||||
|
||||
for (int i = 0; i < _metadataCount; i++) {
|
||||
FLAC__metadata_object_delete(_metadataList[i]);
|
||||
}
|
||||
delete[] _metadataList;
|
||||
_metadataList = 0;
|
||||
_metadataCount = 0;
|
||||
|
||||
FLAC__stream_encoder_delete(_encoder);
|
||||
|
||||
if ((_finalSampleCount != 0) && (_samplesWritten != _finalSampleCount)) {
|
||||
throw gcnew Exception("Samples written differs from the expected sample count.");
|
||||
}
|
||||
|
||||
_tags->Clear ();
|
||||
}
|
||||
|
||||
property Int64 FinalSampleCount {
|
||||
Int64 get() {
|
||||
return _finalSampleCount;
|
||||
}
|
||||
void set(Int64 value) {
|
||||
if (value < 0) {
|
||||
throw gcnew Exception("Invalid final sample count.");
|
||||
}
|
||||
if (_initialized) {
|
||||
throw gcnew Exception("Final sample count cannot be changed after encoding begins.");
|
||||
}
|
||||
_finalSampleCount = value;
|
||||
}
|
||||
}
|
||||
|
||||
property Int32 CompressionLevel {
|
||||
Int32 get() {
|
||||
return _compressionLevel;
|
||||
}
|
||||
void set(Int32 value) {
|
||||
if ((value < 0) || (value > 8)) {
|
||||
throw gcnew Exception("Invalid compression level.");
|
||||
}
|
||||
_compressionLevel = value;
|
||||
}
|
||||
}
|
||||
|
||||
property Boolean Verify {
|
||||
Boolean get() {
|
||||
return _verify;
|
||||
}
|
||||
void set(Boolean value) {
|
||||
_verify = value;
|
||||
}
|
||||
}
|
||||
|
||||
property Int32 PaddingLength {
|
||||
Int32 get() {
|
||||
return _paddingLength;
|
||||
}
|
||||
void set(Int32 value) {
|
||||
if (value < 0) {
|
||||
throw gcnew Exception("Invalid padding length.");
|
||||
}
|
||||
_paddingLength = value;
|
||||
}
|
||||
}
|
||||
|
||||
void SetTags (NameValueCollection^ tags) {
|
||||
_tags = tags;
|
||||
}
|
||||
|
||||
void Write(array<Int32, 2>^ sampleBuffer, Int32 sampleCount) {
|
||||
if (!_initialized) Initialize();
|
||||
|
||||
pin_ptr<Int32> pSampleBuffer = &sampleBuffer[0, 0];
|
||||
|
||||
if (!FLAC__stream_encoder_process_interleaved(_encoder,
|
||||
(const FLAC__int32*)pSampleBuffer, sampleCount))
|
||||
{
|
||||
throw gcnew Exception("An error occurred while encoding.");
|
||||
}
|
||||
|
||||
_samplesWritten += sampleCount;
|
||||
}
|
||||
|
||||
private:
|
||||
FLAC__StreamEncoder *_encoder;
|
||||
bool _initialized;
|
||||
String^ _path;
|
||||
Int64 _finalSampleCount, _samplesWritten;
|
||||
Int32 _bitsPerSample, _channelCount, _sampleRate;
|
||||
Int32 _compressionLevel;
|
||||
Int32 _paddingLength;
|
||||
Boolean _verify;
|
||||
FLAC__StreamMetadata **_metadataList;
|
||||
int _metadataCount;
|
||||
NameValueCollection^ _tags;
|
||||
|
||||
void Initialize() {
|
||||
FLAC__StreamMetadata *padding, *seektable, *vorbiscomment;
|
||||
IntPtr pathChars;
|
||||
FILE *hFile;
|
||||
|
||||
_metadataList = new FLAC__StreamMetadata*[8];
|
||||
_metadataCount = 0;
|
||||
|
||||
if (_finalSampleCount != 0) {
|
||||
seektable = FLAC__metadata_object_new(FLAC__METADATA_TYPE_SEEKTABLE);
|
||||
FLAC__metadata_object_seektable_template_append_spaced_points_by_samples(
|
||||
seektable, _sampleRate * 10, _finalSampleCount);
|
||||
FLAC__metadata_object_seektable_template_sort(seektable, true);
|
||||
_metadataList[_metadataCount++] = seektable;
|
||||
}
|
||||
|
||||
vorbiscomment = FLAC__metadata_object_new(FLAC__METADATA_TYPE_VORBIS_COMMENT);
|
||||
|
||||
for (int tagno = 0; tagno < _tags->Count; tagno++)
|
||||
{
|
||||
String ^ tag_name = _tags->GetKey(tagno);
|
||||
int tag_len = tag_name->Length;
|
||||
char * tag = new char [tag_len + 1];
|
||||
IntPtr nameChars = Marshal::StringToHGlobalAnsi(tag_name);
|
||||
memcpy (tag, (const char*)nameChars.ToPointer(), tag_len);
|
||||
Marshal::FreeHGlobal(nameChars);
|
||||
tag[tag_len] = 0;
|
||||
|
||||
array<String^>^ tag_values = _tags->GetValues(tagno);
|
||||
for (int valno = 0; valno < tag_values->Length; valno++)
|
||||
{
|
||||
UTF8Encoding^ enc = gcnew UTF8Encoding();
|
||||
array<Byte>^ value_array = enc->GetBytes (tag_values[valno]);
|
||||
int value_len = value_array->Length;
|
||||
char * value = new char [value_len + 1];
|
||||
Marshal::Copy (value_array, 0, (IntPtr) value, value_len);
|
||||
value[value_len] = 0;
|
||||
|
||||
FLAC__StreamMetadata_VorbisComment_Entry entry;
|
||||
/* create and entry and append it */
|
||||
if(!FLAC__metadata_object_vorbiscomment_entry_from_name_value_pair(&entry, tag, value)) {
|
||||
throw gcnew Exception("Unable to add tags, must be valid utf8.");
|
||||
}
|
||||
if(!FLAC__metadata_object_vorbiscomment_append_comment(vorbiscomment, entry, /*copy=*/false)) {
|
||||
throw gcnew Exception("Unable to add tags.");
|
||||
}
|
||||
delete [] value;
|
||||
}
|
||||
delete [] tag;
|
||||
}
|
||||
_metadataList[_metadataCount++] = vorbiscomment;
|
||||
|
||||
if (_paddingLength != 0) {
|
||||
padding = FLAC__metadata_object_new(FLAC__METADATA_TYPE_PADDING);
|
||||
padding->length = _paddingLength;
|
||||
_metadataList[_metadataCount++] = padding;
|
||||
}
|
||||
|
||||
FLAC__stream_encoder_set_metadata(_encoder, _metadataList, _metadataCount);
|
||||
|
||||
FLAC__stream_encoder_set_verify(_encoder, _verify);
|
||||
|
||||
if (_finalSampleCount != 0) {
|
||||
FLAC__stream_encoder_set_total_samples_estimate(_encoder, _finalSampleCount);
|
||||
}
|
||||
|
||||
FLAC__stream_encoder_set_compression_level(_encoder, _compressionLevel);
|
||||
|
||||
pathChars = Marshal::StringToHGlobalUni(_path);
|
||||
hFile = _wfopen((const wchar_t*)pathChars.ToPointer(), L"w+b");
|
||||
Marshal::FreeHGlobal(pathChars);
|
||||
|
||||
if (FLAC__stream_encoder_init_FILE(_encoder, hFile, NULL, NULL) !=
|
||||
FLAC__STREAM_ENCODER_INIT_STATUS_OK)
|
||||
{
|
||||
throw gcnew Exception("Unable to initialize the encoder.");
|
||||
}
|
||||
|
||||
_initialized = true;
|
||||
}
|
||||
};
|
||||
}
|
||||
3
FLACDotNet/resource.h
Normal file
3
FLACDotNet/resource.h
Normal file
@@ -0,0 +1,3 @@
|
||||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by app.rc
|
||||
Reference in New Issue
Block a user