mirror of
https://github.com/claunia/cuetools.net.git
synced 2025-12-16 18:14:25 +00:00
Code cleanup; Reader classes renamed to Decoders, Writers to Encoders, every Decoder must have a corresponding Settings class now just like Encoders. UserDefinedEncoders renamed to CommandLineEncoders, etc.
This commit is contained in:
29
CUETools.Codecs.libmp3lame/CUETools.Codecs.libmp3lame.csproj
Normal file
29
CUETools.Codecs.libmp3lame/CUETools.Codecs.libmp3lame.csproj
Normal file
@@ -0,0 +1,29 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net40;net20;netstandard2.0</TargetFrameworks>
|
||||
<Version>2.1.7.0</Version>
|
||||
<AssemblyName>CUETools.Codecs.libmp3lame</AssemblyName>
|
||||
<RootNamespace>CUETools.Codecs.libmp3lame</RootNamespace>
|
||||
<Product>CUETools</Product>
|
||||
<Description>A library for encoding mp3 using LAME encoder.</Description>
|
||||
<Copyright>Copyright (c) 2008-2018 Grigory Chudov</Copyright>
|
||||
<Authors>Grigory Chudov</Authors>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<OutputPath>..\bin\$(Configuration)\plugins</OutputPath>
|
||||
<RepositoryUrl>https://github.com/gchudov/cuetools.net</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<Company />
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemDefinitionGroup>
|
||||
<ProjectReference>
|
||||
<Private>False</Private>
|
||||
</ProjectReference>
|
||||
</ItemDefinitionGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\CUETools.Codecs\CUETools.Codecs.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
14
CUETools.Codecs.libmp3lame/LameException.cs
Normal file
14
CUETools.Codecs.libmp3lame/LameException.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace CUETools.Codecs.libmp3lame
|
||||
{
|
||||
public class LameException : Exception
|
||||
{
|
||||
public LameException(string message)
|
||||
: base(message)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
259
CUETools.Codecs.libmp3lame/LameWriter.cs
Normal file
259
CUETools.Codecs.libmp3lame/LameWriter.cs
Normal file
@@ -0,0 +1,259 @@
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using CUETools.Codecs;
|
||||
using System.IO;
|
||||
|
||||
namespace CUETools.Codecs.libmp3lame
|
||||
{
|
||||
public class AudioEncoder : IAudioDest
|
||||
{
|
||||
private string m_outputPath;
|
||||
private Stream m_outputStream;
|
||||
|
||||
private bool m_closed = false, m_initialized = false;
|
||||
private IntPtr m_handle;
|
||||
private uint m_finalSampleCount;
|
||||
private byte[] m_outputBuffer;
|
||||
private long m_bytesWritten;
|
||||
|
||||
public long FinalSampleCount
|
||||
{
|
||||
set
|
||||
{
|
||||
if (value > uint.MaxValue)
|
||||
{
|
||||
throw new ArgumentException("Input file too big.");
|
||||
}
|
||||
this.m_finalSampleCount = (uint)value;
|
||||
}
|
||||
}
|
||||
|
||||
public string Path
|
||||
{
|
||||
get { return this.m_outputPath; }
|
||||
}
|
||||
|
||||
private LameEncoderSettings m_settings;
|
||||
|
||||
public virtual AudioEncoderSettings Settings
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_settings;
|
||||
}
|
||||
}
|
||||
|
||||
public long BytesWritten => m_bytesWritten;
|
||||
|
||||
public AudioEncoder(LameEncoderSettings settings, string path, Stream output = null)
|
||||
{
|
||||
this.CheckPCMConfig(settings.PCM);
|
||||
this.m_settings = settings;
|
||||
this.m_outputPath = path;
|
||||
this.m_outputStream = output != null ? output : File.Create(path);
|
||||
this.m_bytesWritten = 0;
|
||||
}
|
||||
|
||||
private void CheckPCMConfig(AudioPCMConfig pcm)
|
||||
{
|
||||
if (pcm.BitsPerSample != 16)
|
||||
{
|
||||
throw new ArgumentException("LAME only supports 16 bits/sample.");
|
||||
}
|
||||
}
|
||||
|
||||
private void FinalizeEncoding()
|
||||
{
|
||||
this.EnsureOutputBufferSize(7200);
|
||||
|
||||
int flushResult;
|
||||
unsafe
|
||||
{
|
||||
fixed (byte* outputBufferPtr = m_outputBuffer)
|
||||
{
|
||||
flushResult = libmp3lamedll.lame_encode_flush(m_handle, (IntPtr)outputBufferPtr, m_outputBuffer.Length);
|
||||
}
|
||||
}
|
||||
if (flushResult < 0)
|
||||
{
|
||||
throw new LameException("Unknown flush error");
|
||||
}
|
||||
if (flushResult > 0)
|
||||
{
|
||||
this.m_outputStream.Write(this.m_outputBuffer, 0, flushResult);
|
||||
m_bytesWritten += flushResult;
|
||||
}
|
||||
|
||||
int lametagFrameSize = this.GetLametagFrame();
|
||||
this.m_outputStream.Seek(0, SeekOrigin.Begin);
|
||||
this.m_outputStream.Write(this.m_outputBuffer, 0, lametagFrameSize);
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
if (!this.m_closed)
|
||||
{
|
||||
if (this.m_initialized)
|
||||
{
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
this.FinalizeEncoding();
|
||||
}
|
||||
finally
|
||||
{
|
||||
libmp3lamedll.lame_close(m_handle);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
m_handle = IntPtr.Zero;
|
||||
if (this.m_outputPath != null)
|
||||
{
|
||||
this.m_outputStream.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.m_closed = true;
|
||||
}
|
||||
}
|
||||
|
||||
private int GetLametagFrame()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
uint lametagFrameResult;
|
||||
unsafe
|
||||
{
|
||||
fixed (byte* outputBufferPtr = m_outputBuffer)
|
||||
{
|
||||
lametagFrameResult = libmp3lamedll.lame_get_lametag_frame(this.m_handle, (IntPtr)outputBufferPtr, (uint)m_outputBuffer.Length);
|
||||
}
|
||||
}
|
||||
if (lametagFrameResult < 0)
|
||||
{
|
||||
throw new LameException("Error getting lametag frame.");
|
||||
}
|
||||
if (lametagFrameResult <= m_outputBuffer.Length)
|
||||
{
|
||||
return (int)lametagFrameResult;
|
||||
}
|
||||
this.EnsureOutputBufferSize((int)lametagFrameResult);
|
||||
}
|
||||
}
|
||||
|
||||
public uint GetLametagFrame(byte[] outputBuffer)
|
||||
{
|
||||
unsafe
|
||||
{
|
||||
fixed (byte* outputBufferPtr = outputBuffer)
|
||||
{
|
||||
return libmp3lamedll.lame_get_lametag_frame(m_handle, (IntPtr)outputBufferPtr, (uint)outputBuffer.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void EnsureInitialized()
|
||||
{
|
||||
if (!this.m_initialized)
|
||||
{
|
||||
m_handle = libmp3lamedll.lame_init();
|
||||
|
||||
libmp3lamedll.lame_set_bWriteVbrTag(m_handle, 1);
|
||||
libmp3lamedll.lame_set_write_id3tag_automatic(m_handle, 0);
|
||||
|
||||
libmp3lamedll.lame_set_num_channels(m_handle, this.Settings.PCM.ChannelCount);
|
||||
libmp3lamedll.lame_set_in_samplerate(m_handle, this.Settings.PCM.SampleRate);
|
||||
|
||||
if (this.m_finalSampleCount != 0)
|
||||
{
|
||||
libmp3lamedll.lame_set_num_samples(m_handle, this.m_finalSampleCount);
|
||||
}
|
||||
|
||||
m_settings.Apply(m_handle);
|
||||
|
||||
if (libmp3lamedll.lame_init_params(m_handle) != 0)
|
||||
{
|
||||
throw new LameException("lame_init_params failed");
|
||||
}
|
||||
|
||||
this.m_initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void Delete()
|
||||
{
|
||||
if (this.m_outputPath == null)
|
||||
{
|
||||
throw new InvalidOperationException("This writer was not created from file.");
|
||||
}
|
||||
|
||||
if (!m_closed)
|
||||
{
|
||||
this.Close();
|
||||
File.Delete(this.m_outputPath);
|
||||
}
|
||||
}
|
||||
|
||||
private void EnsureOutputBufferSize(int requiredSize)
|
||||
{
|
||||
if (this.m_outputBuffer == null || this.m_outputBuffer.Length < requiredSize)
|
||||
{
|
||||
this.m_outputBuffer = new byte[requiredSize];
|
||||
}
|
||||
}
|
||||
|
||||
public void Write(AudioBuffer buffer)
|
||||
{
|
||||
if (this.m_closed)
|
||||
{
|
||||
throw new InvalidOperationException("Writer already closed.");
|
||||
}
|
||||
|
||||
buffer.Prepare(this);
|
||||
|
||||
this.EnsureInitialized();
|
||||
|
||||
this.EnsureOutputBufferSize(buffer.Length * 5 / 4 + 7200);
|
||||
|
||||
byte[] bytes = buffer.Bytes;
|
||||
|
||||
int result;
|
||||
unsafe
|
||||
{
|
||||
fixed (byte* bytesPtr = bytes)
|
||||
{
|
||||
fixed (byte* outputBufferPtr = this.m_outputBuffer)
|
||||
{
|
||||
result = libmp3lamedll.lame_encode_buffer_interleaved(m_handle, (IntPtr)bytesPtr, buffer.Length, (IntPtr)outputBufferPtr, m_outputBuffer.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result < 0)
|
||||
{
|
||||
switch (result)
|
||||
{
|
||||
case -1:
|
||||
throw new LameException("Output buffer is too small");
|
||||
case -2:
|
||||
throw new LameException("malloc problem");
|
||||
case -3:
|
||||
throw new LameException("lame_init_params was not called");
|
||||
case -4:
|
||||
throw new LameException("Psycho acoustic problems");
|
||||
default:
|
||||
throw new LameException("Unknown error");
|
||||
}
|
||||
}
|
||||
|
||||
if (result > 0)
|
||||
{
|
||||
this.m_outputStream.Write(this.m_outputBuffer, 0, result);
|
||||
m_bytesWritten += result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
36
CUETools.Codecs.libmp3lame/LameWriterCBRSettings.cs
Normal file
36
CUETools.Codecs.libmp3lame/LameWriterCBRSettings.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Text;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace CUETools.Codecs.libmp3lame
|
||||
{
|
||||
[JsonObject(MemberSerialization.OptIn)]
|
||||
public class CBREncoderSettings : LameEncoderSettings
|
||||
{
|
||||
public override string Extension => "mp3";
|
||||
|
||||
public override string Name => "libmp3lame-CBR";
|
||||
|
||||
public override int Priority => 1;
|
||||
|
||||
public static readonly int[] bps_table = new int[] { 96, 128, 192, 256, 320 };
|
||||
|
||||
[JsonProperty]
|
||||
[DefaultValue(LameQuality.High)]
|
||||
public LameQuality Quality { get; set; }
|
||||
|
||||
public CBREncoderSettings()
|
||||
: base("96 128 192 256 320", "256")
|
||||
{
|
||||
}
|
||||
|
||||
public override void Apply(IntPtr lame)
|
||||
{
|
||||
libmp3lamedll.lame_set_VBR(lame, (int)LameVbrMode.Off);
|
||||
libmp3lamedll.lame_set_brate(lame, CBREncoderSettings.bps_table[this.EncoderModeIndex]);
|
||||
libmp3lamedll.lame_set_quality(lame, (int)this.Quality);
|
||||
}
|
||||
}
|
||||
}
|
||||
22
CUETools.Codecs.libmp3lame/LameWriterConstants.cs
Normal file
22
CUETools.Codecs.libmp3lame/LameWriterConstants.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace CUETools.Codecs.libmp3lame
|
||||
{
|
||||
public enum LameQuality
|
||||
{
|
||||
High = 2,
|
||||
Normal = 5,
|
||||
Fast = 7,
|
||||
}
|
||||
|
||||
public enum LameVbrMode
|
||||
{
|
||||
Off = 0,
|
||||
Mt = 1,
|
||||
Rh = 2,
|
||||
Abr = 3,
|
||||
Default = 4,
|
||||
}
|
||||
}
|
||||
21
CUETools.Codecs.libmp3lame/LameWriterSettings.cs
Normal file
21
CUETools.Codecs.libmp3lame/LameWriterSettings.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace CUETools.Codecs.libmp3lame
|
||||
{
|
||||
public class LameEncoderSettings : AudioEncoderSettings
|
||||
{
|
||||
public override Type EncoderType => typeof(AudioEncoder);
|
||||
|
||||
public LameEncoderSettings(string modes, string defaultMode)
|
||||
: base(modes, defaultMode)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void Apply(IntPtr lame)
|
||||
{
|
||||
throw new MethodAccessException();
|
||||
}
|
||||
}
|
||||
}
|
||||
34
CUETools.Codecs.libmp3lame/LameWriterVBRSettings.cs
Normal file
34
CUETools.Codecs.libmp3lame/LameWriterVBRSettings.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Text;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace CUETools.Codecs.libmp3lame
|
||||
{
|
||||
[JsonObject(MemberSerialization.OptIn)]
|
||||
public class VBREncoderSettings : LameEncoderSettings
|
||||
{
|
||||
public override string Extension => "mp3";
|
||||
|
||||
public override string Name => "libmp3lame-VBR";
|
||||
|
||||
public override int Priority => 2;
|
||||
|
||||
[JsonProperty]
|
||||
[DefaultValue(LameQuality.High)]
|
||||
public LameQuality Quality { get; set; }
|
||||
|
||||
public VBREncoderSettings()
|
||||
: base("V9 V8 V7 V6 V5 V4 V3 V2 V1 V0", "V2")
|
||||
{
|
||||
}
|
||||
|
||||
public override void Apply(IntPtr lame)
|
||||
{
|
||||
libmp3lamedll.lame_set_VBR(lame, (int)LameVbrMode.Default);
|
||||
libmp3lamedll.lame_set_VBR_quality(lame, 9 - this.EncoderModeIndex);
|
||||
libmp3lamedll.lame_set_quality(lame, (int)this.Quality);
|
||||
}
|
||||
}
|
||||
}
|
||||
66
CUETools.Codecs.libmp3lame/libmp3lamedll.cs
Normal file
66
CUETools.Codecs.libmp3lame/libmp3lamedll.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace CUETools.Codecs.libmp3lame
|
||||
{
|
||||
class libmp3lamedll
|
||||
{
|
||||
private const string DllName = "libmp3lame";
|
||||
private const CallingConvention LameCallingConvention = CallingConvention.Cdecl;
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
private static extern IntPtr LoadLibrary(string dllToLoad);
|
||||
|
||||
[DllImport(DllName, CallingConvention = LameCallingConvention)]
|
||||
internal static extern IntPtr lame_init();
|
||||
[DllImport(DllName, CallingConvention = LameCallingConvention)]
|
||||
internal static extern int lame_close(IntPtr handle);
|
||||
[DllImport(DllName, CallingConvention = LameCallingConvention)]
|
||||
internal static extern int lame_set_num_channels(IntPtr handle, int channels);
|
||||
[DllImport(DllName, CallingConvention = LameCallingConvention)]
|
||||
internal static extern int lame_set_in_samplerate(IntPtr handle, int sampleRate);
|
||||
[DllImport(DllName, CallingConvention = LameCallingConvention)]
|
||||
internal static extern int lame_set_quality(IntPtr handle, int quality);
|
||||
[DllImport(DllName, CallingConvention = LameCallingConvention)]
|
||||
internal static extern int lame_set_VBR(IntPtr handle, int vbrMode);
|
||||
[DllImport(DllName, CallingConvention = LameCallingConvention)]
|
||||
internal static extern int lame_set_VBR_mean_bitrate_kbps(IntPtr handle, int meanBitrate);
|
||||
[DllImport(DllName, CallingConvention = LameCallingConvention)]
|
||||
internal static extern int lame_init_params(IntPtr handle);
|
||||
[DllImport(DllName, CallingConvention = LameCallingConvention)]
|
||||
internal static extern int lame_set_num_samples(IntPtr handle, uint numSamples);
|
||||
[DllImport(DllName, CallingConvention = LameCallingConvention)]
|
||||
internal static extern int lame_encode_buffer_interleaved(IntPtr handle, IntPtr pcm, int num_samples, IntPtr mp3buf, int mp3buf_size);
|
||||
[DllImport(DllName, CallingConvention = LameCallingConvention)]
|
||||
internal static extern int lame_encode_flush(IntPtr handle, IntPtr mp3buf, int size);
|
||||
[DllImport(DllName, CallingConvention = LameCallingConvention)]
|
||||
internal static extern uint lame_get_lametag_frame(IntPtr handle, IntPtr buffer, uint size);
|
||||
[DllImport(DllName, CallingConvention = LameCallingConvention)]
|
||||
internal static extern int lame_set_VBR_quality(IntPtr handle, float vbrQuality);
|
||||
[DllImport(DllName, CallingConvention = LameCallingConvention)]
|
||||
internal static extern int lame_set_brate(IntPtr handle, int bitrate);
|
||||
[DllImport(DllName, CallingConvention = LameCallingConvention)]
|
||||
internal static extern int lame_set_bWriteVbrTag(IntPtr handle, int writeVbrTag);
|
||||
[DllImport(DllName, CallingConvention = LameCallingConvention)]
|
||||
internal static extern int lame_set_write_id3tag_automatic(IntPtr handle, int automaticWriteId3Tag);
|
||||
|
||||
static libmp3lamedll()
|
||||
{
|
||||
var myPath = new Uri(typeof(libmp3lamedll).Assembly.CodeBase).LocalPath;
|
||||
var myFolder = System.IO.Path.GetDirectoryName(myPath);
|
||||
var is64 = IntPtr.Size == 8;
|
||||
var subfolder = is64 ? "x64" : "win32";
|
||||
#if NET40
|
||||
IntPtr Dll = LoadLibrary(System.IO.Path.Combine(myFolder, subfolder, DllName + ".dll"));
|
||||
#else
|
||||
IntPtr Dll = LoadLibrary(System.IO.Path.Combine(System.IO.Path.Combine(myFolder, subfolder), DllName + ".dll"));
|
||||
#endif
|
||||
if (Dll == IntPtr.Zero)
|
||||
Dll = LoadLibrary(DllName + ".dll");
|
||||
if (Dll == IntPtr.Zero)
|
||||
throw new DllNotFoundException();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user