Last active
November 30, 2023 03:36
-
-
Save snightshade/fb20be973e71fca522ce78026313ce6b to your computer and use it in GitHub Desktop.
320ifier
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Diagnostics; | |
// 320ifier - parallel automatic bulk transcoding toolkit | |
// 2023 nightshades-madoka | |
// warning: this program will use as many cores as it can, be careful | |
// MIT license or whatever idgaf what you do with this | |
namespace ThreeHundredTwentyfier; | |
public class Program | |
{ | |
enum Mode | |
{ | |
To320, | |
To16bit, | |
ToV0 | |
} | |
private class WorkUnit | |
{ | |
public ProcessStartInfo Info = null!; | |
public uint ThreadId; | |
public string FileName = ""; | |
public uint WorkId; | |
} | |
static List<WorkUnit> GetPsiList(Mode mode) | |
{ | |
var list = new List<WorkUnit>(); | |
var baseDir = Path.GetFileName(Environment.CurrentDirectory); | |
Directory.CreateDirectory(baseDir); | |
var procCount = Environment.ProcessorCount; | |
var currentThread = 0u; | |
var currentId = 0u; | |
var dir = Directory.EnumerateFiles("input"); | |
foreach (var f in dir) | |
{ | |
var filename = Path.GetFileNameWithoutExtension(f); | |
var psi = mode switch | |
{ | |
Mode.To320 => new ProcessStartInfo | |
{ | |
FileName = @"C:\bin\ffmpeg.exe", | |
Arguments = $""" | |
-y -i "input\{filename}.flac" -ab 320k -map_metadata 0 -id3v2_version 3 "{baseDir}\{filename}.mp3" | |
""" | |
}, | |
Mode.To16bit => new ProcessStartInfo | |
{ | |
FileName = @"C:\bin\ffmpeg.exe", | |
Arguments = $""" | |
-y -i "input\{filename}.flac" -sample_fmt s16 "{baseDir}\{filename}.flac" | |
""" | |
}, | |
Mode.ToV0 => new ProcessStartInfo | |
{ | |
FileName = @"C:\bin\ffmpeg.exe", | |
Arguments = $""" | |
-y -i "input\{filename}.flac" -c:a libmp3lame -q:a 0 -map_metadata 0 -id3v2_version 3 "{baseDir}\{filename}.mp3" | |
""" | |
}, | |
_ => throw new ArgumentOutOfRangeException(nameof(mode)) | |
}; | |
psi.CreateNoWindow = true; | |
psi.RedirectStandardOutput = true; | |
list.Add(new() | |
{ | |
Info = psi, | |
ThreadId = currentThread++, | |
FileName = filename, | |
WorkId = currentId++ | |
}); | |
if (currentThread >= procCount) currentThread = 0; | |
} | |
return list; | |
} | |
public static void Main(string[] args) | |
{ | |
var mode = Mode.To320; | |
if (args.Length > 0) | |
{ | |
switch (args[0]) | |
{ | |
case "16bit": | |
Console.WriteLine("16-bit mode"); | |
mode = Mode.To16bit; | |
break; | |
case "v0": | |
Console.WriteLine("v0 mode"); | |
mode = Mode.ToV0; | |
break; | |
} | |
} | |
var processStartInfoList = GetPsiList(mode); | |
var fileCount = processStartInfoList.Count; | |
var psiSlots = Environment.ProcessorCount; | |
if (psiSlots > fileCount) psiSlots = fileCount; | |
Console.WriteLine($"Starting {psiSlots} threads"); | |
var complete = 0; | |
var threads = new List<Thread>(); | |
var timeAtStart = Stopwatch.GetTimestamp(); | |
for (uint i = 0; i < psiSlots; i++) | |
{ | |
var threadId = i; | |
var thread = new Thread(() => | |
{ | |
var done = new List<uint>(); | |
while (true) | |
{ | |
if (processStartInfoList.Count == 0) break; | |
var psi = processStartInfoList.FirstOrDefault(x => | |
x.ThreadId == threadId && !done.Contains(x.WorkId)); | |
if (psi == null) break; | |
Console.WriteLine($"Thread {threadId} picked up '{psi.FileName}'"); | |
var process = Process.Start(psi.Info)!; | |
process.WaitForExit(); | |
done.Add(psi.WorkId); | |
Console.WriteLine($"Thread {threadId} finished '{psi.FileName}' ({++complete}/{fileCount})"); | |
} | |
Console.WriteLine($"Thread {threadId} exhausted work pool"); | |
}); | |
thread.Start(); | |
threads.Add(thread); | |
} | |
foreach (var t in threads) t.Join(); | |
var timeAtEnd = Stopwatch.GetElapsedTime(timeAtStart); | |
Console.WriteLine(timeAtEnd.TotalSeconds > 60 | |
? $"Complete! Took {timeAtEnd.TotalMinutes}m:{timeAtEnd.TotalSeconds % 60}s." | |
: $"Complete! Took {timeAtEnd.TotalSeconds} seconds."); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment