175 lines
5.8 KiB
C#
175 lines
5.8 KiB
C#
using Li.Utilities;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Linq;
|
|
using System.Runtime.InteropServices;
|
|
using System.Text;
|
|
using System.Threading.Channels;
|
|
using System.Threading.Tasks;
|
|
using System.Xml.Linq;
|
|
|
|
namespace GameBuilder.Atrac3
|
|
{
|
|
public class Atrac3ToolEncoder : IAtracEncoderBase
|
|
{
|
|
[DllImport("libc")]
|
|
private static extern int setenv(string name, string value, bool overwrite);
|
|
|
|
private static Random rng = new Random();
|
|
private static string TOOLS_DIRECTORY = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "tools");
|
|
|
|
private static string AT3TOOL_WIN = Path.Combine(TOOLS_DIRECTORY, "at3tool.exe");
|
|
private static string AT3TOOL_LINUX = Path.Combine(TOOLS_DIRECTORY, "at3tool.elf");
|
|
|
|
private static string TEMP_DIRECTORY = Path.Combine(Path.GetTempPath(), "at3tool_tmp");
|
|
private static string LD_LIBRARY_PATH = "LD_LIBRARY_PATH";
|
|
|
|
// random name so that can generate multiple at once if wanted ..
|
|
private string TEMP_WAV;
|
|
private string TEMP_AT3;
|
|
public Atrac3ToolEncoder()
|
|
{
|
|
string rdmPart = rng.Next().ToString("X");
|
|
|
|
TEMP_WAV = Path.Combine(TEMP_DIRECTORY, rdmPart + "_tmp.wav");
|
|
TEMP_AT3 = Path.Combine(TEMP_DIRECTORY, rdmPart + "_tmp.at3");
|
|
|
|
}
|
|
|
|
private static string AT3TOOL_LOCATION
|
|
{
|
|
get
|
|
{
|
|
if (OperatingSystem.IsWindows())
|
|
return AT3TOOL_WIN;
|
|
else if (OperatingSystem.IsLinux())
|
|
return AT3TOOL_LINUX;
|
|
else
|
|
throw new PlatformNotSupportedException("No at3tool binary for your platform");
|
|
}
|
|
}
|
|
|
|
private string setupLibaryPath()
|
|
{
|
|
string? libaryPath = Environment.GetEnvironmentVariable(LD_LIBRARY_PATH);
|
|
if (libaryPath is null) libaryPath = TOOLS_DIRECTORY;
|
|
else libaryPath += ";" + TOOLS_DIRECTORY;
|
|
|
|
Environment.SetEnvironmentVariable(libaryPath, libaryPath);
|
|
setenv(LD_LIBRARY_PATH, libaryPath, true);
|
|
|
|
return libaryPath;
|
|
}
|
|
private void runAtrac3Tool()
|
|
{
|
|
using(Process proc = new Process())
|
|
{
|
|
if (OperatingSystem.IsLinux())
|
|
proc.StartInfo.Environment.Add(LD_LIBRARY_PATH, setupLibaryPath());
|
|
|
|
proc.StartInfo.FileName = AT3TOOL_LOCATION;
|
|
proc.StartInfo.Arguments = "-br 132 -e \"" + TEMP_WAV + "\" \"" + TEMP_AT3 + "\"";
|
|
|
|
proc.StartInfo.UseShellExecute = false;
|
|
proc.StartInfo.CreateNoWindow = true;
|
|
proc.StartInfo.RedirectStandardOutput = true;
|
|
proc.StartInfo.RedirectStandardInput = true;
|
|
|
|
proc.Start();
|
|
proc.WaitForExit();
|
|
|
|
string stdout = proc.StandardOutput.ReadToEnd();
|
|
if (!stdout.Contains("Total Encoded Bytes"))
|
|
throw new Exception(stdout);
|
|
}
|
|
}
|
|
|
|
private byte[] stripAtracHeader()
|
|
{
|
|
using(FileStream at3Stream = File.OpenRead(TEMP_AT3))
|
|
{
|
|
StreamUtil at3Util = new StreamUtil(at3Stream);
|
|
at3Stream.Seek(0x4C, SeekOrigin.Begin);
|
|
int at3Len = at3Util.ReadInt32();
|
|
return at3Util.ReadBytes(at3Len);
|
|
}
|
|
}
|
|
|
|
private void makeWav(byte[] pcmData)
|
|
{
|
|
using (FileStream wavStream = File.Open(TEMP_WAV, FileMode.Create))
|
|
{
|
|
// CD-AUDIO standard settings
|
|
int fileSize = pcmData.Length;
|
|
int samplerate = 44100;
|
|
short channels = 2; // channels
|
|
short format = 16; // signed, 16 bit PCM
|
|
|
|
StreamUtil wavUtil = new StreamUtil(wavStream);
|
|
|
|
wavUtil.WriteStr("RIFF");
|
|
wavUtil.WriteInt32((fileSize + (0x2C - 8)));
|
|
|
|
wavUtil.WriteStr("WAVE");
|
|
wavUtil.WriteStr("fmt ");
|
|
wavUtil.WriteInt32(format);
|
|
|
|
wavUtil.WriteInt16(1);
|
|
wavUtil.WriteInt16(channels);
|
|
wavUtil.WriteInt32(samplerate);
|
|
wavUtil.WriteInt32((samplerate * format * channels) / 8);
|
|
wavUtil.WriteInt16(Convert.ToInt16(format * channels));
|
|
wavUtil.WriteInt16(format);
|
|
|
|
wavUtil.WriteStr("data");
|
|
wavUtil.WriteInt32(fileSize);
|
|
wavUtil.WriteBytes(pcmData);
|
|
}
|
|
}
|
|
|
|
private void ensureFilesAvailable()
|
|
{
|
|
if (!Directory.Exists(TEMP_DIRECTORY))
|
|
Directory.CreateDirectory(TEMP_DIRECTORY);
|
|
|
|
if (!Directory.Exists(TOOLS_DIRECTORY))
|
|
Directory.CreateDirectory(TOOLS_DIRECTORY);
|
|
|
|
if (OperatingSystem.IsWindows())
|
|
{
|
|
if (!File.Exists(AT3TOOL_WIN))
|
|
{
|
|
throw new FileNotFoundException("Cannot find at3tool at " + AT3TOOL_WIN);
|
|
}
|
|
}
|
|
else if(OperatingSystem.IsLinux())
|
|
{
|
|
if (!File.Exists(AT3TOOL_LINUX))
|
|
{
|
|
throw new FileNotFoundException("Cannot find at3tool at " + AT3TOOL_LINUX);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void cleanup()
|
|
{
|
|
if (File.Exists(TEMP_WAV)) File.Delete(TEMP_WAV);
|
|
if (File.Exists(TEMP_AT3)) File.Delete(TEMP_AT3);
|
|
}
|
|
|
|
public byte[] EncodeToAtrac(byte[] pcmData)
|
|
{
|
|
ensureFilesAvailable();
|
|
|
|
makeWav(pcmData);
|
|
runAtrac3Tool();
|
|
byte[] rawAtracData = stripAtracHeader();
|
|
|
|
cleanup();
|
|
|
|
return rawAtracData;
|
|
}
|
|
}
|
|
}
|