static void Main(string[] args) { if (args.Length < 1) { Console.WriteLine("Usage: audio.clt converted_audio.wav"); return; } string outPath = (args.Length > 1) ? args[1] : Path.Combine(Path.GetDirectoryName(args[0]), $"{Path.GetFileNameWithoutExtension(args[0])}.wav"); try { Celt celt = Celt.FromFile(args[0]); celt.WriteToWavFile(outPath); } catch (Exception ex) { Console.WriteLine("Error: {0}", ex.Message); return; } Console.WriteLine("Successfully wrote output wav file to {0}", outPath); }
static void Main(string[] args) { if (args.Length < 2) { Console.WriteLine("Usage: audio.clt converted_audio.wav"); return; } try { Celt celt = Celt.FromFile(args[0]); celt.WriteToWavFile(args[1]); } catch (Exception ex) { Console.WriteLine("Error: {0}", ex.Message); return; } Console.WriteLine("Successfully wrote output wav file to {0}", args[1]); }
static void AudioEncoder(AudioEncoderOptions options) { bool IsCeltFile(string path) { string ext = Path.GetExtension(path); return(ext.Equals(".clt", StringComparison.CurrentCultureIgnoreCase)); } // Imports audio file Celt celt = IsCeltFile(options.InputPath) ? Celt.FromFile(options.InputPath) : Celt.FromAudio(options.InputPath); Console.WriteLine($"Opened {options.InputPath}"); string o = options.OutputPath; // Exports audio file if (IsCeltFile(o)) { celt.Export(o); } else { o = Path.Combine(Path.GetDirectoryName(o), Path.GetFileNameWithoutExtension(o)) + ".wav"; // Creates directory if it doesn't exist if (!Directory.Exists(Path.GetDirectoryName(o))) { Directory.CreateDirectory(Path.GetDirectoryName(o)); } celt.WriteToWavFile(o); } Console.WriteLine($"Saved {o}"); }
protected override Task <ResultStatus> DoCommandOverride(ICommandContext commandContext) { var assetManager = new ContentManager(); // Get absolute path of asset source on disk var assetDirectory = Parameters.Source.GetParent(); var assetSource = UPath.Combine(assetDirectory, Parameters.Source); var installationDir = DirectoryHelper.GetPackageDirectory("Xenko"); var binDir = UPath.Combine(installationDir, new UDirectory("Bin")); binDir = UPath.Combine(binDir, new UDirectory("Windows")); var ffmpeg = UPath.Combine(binDir, new UFile("ffmpeg.exe")); if (!File.Exists(ffmpeg)) { throw new AssetException("Failed to compile a sound asset, ffmpeg was not found."); } var channels = Parameters.Spatialized ? 1 : 2; var tempPcmFile = Path.GetTempFileName(); var ret = RunProcessAndGetOutput(ffmpeg, $"-i \"{assetSource}\" -f f32le -acodec pcm_f32le -ac {channels} -ar {Parameters.SampleRate} -y \"{tempPcmFile}\""); if (ret != 0) { File.Delete(tempPcmFile); throw new AssetException($"Failed to compile a sound asset, ffmpeg failed to convert {assetSource}"); } var encoder = new Celt(Parameters.SampleRate, CompressedSoundSource.SamplesPerFrame, channels, false); var uncompressed = CompressedSoundSource.SamplesPerFrame * channels * sizeof(short); //compare with int16 for CD quality comparison.. but remember we are dealing with 32 bit floats for encoding!! var target = (int)Math.Floor(uncompressed / (float)Parameters.CompressionRatio); var dataUrl = Url + "_Data"; var newSound = new Sound { CompressedDataUrl = dataUrl, Channels = channels, SampleRate = Parameters.SampleRate, StreamFromDisk = Parameters.StreamFromDisk, Spatialized = Parameters.Spatialized, }; //make sure we don't compress celt data commandContext.AddTag(new ObjectUrl(UrlType.ContentLink, dataUrl), disableCompressionSymbol); var frameSize = CompressedSoundSource.SamplesPerFrame * channels; using (var reader = new BinaryReader(new FileStream(tempPcmFile, FileMode.Open, FileAccess.Read))) using (var outputStream = ContentManager.FileProvider.OpenStream(dataUrl, VirtualFileMode.Create, VirtualFileAccess.Write, VirtualFileShare.Read, StreamFlags.Seekable)) { var writer = new BinarySerializationWriter(outputStream); var outputBuffer = new byte[target]; var buffer = new float[frameSize]; var count = 0; var length = reader.BaseStream.Length; // Cache the length, because this getter is expensive to use for (var position = 0; position < length; position += sizeof(float)) { if (count == frameSize) //flush { var len = encoder.Encode(buffer, outputBuffer); writer.Write((short)len); outputStream.Write(outputBuffer, 0, len); count = 0; Array.Clear(buffer, 0, frameSize); newSound.NumberOfPackets++; newSound.MaxPacketLength = Math.Max(newSound.MaxPacketLength, len); } buffer[count] = reader.ReadSingle(); count++; } if (count > 0) //flush { var len = encoder.Encode(buffer, outputBuffer); writer.Write((short)len); outputStream.Write(outputBuffer, 0, len); newSound.NumberOfPackets++; newSound.MaxPacketLength = Math.Max(newSound.MaxPacketLength, len); } } File.Delete(tempPcmFile); assetManager.Save(Url, newSound); return(Task.FromResult(ResultStatus.Successful)); }
/// <inheritdoc /> protected override async Task <ResultStatus> DoCommandOverride(ICommandContext commandContext) { // Get path to ffmpeg var ffmpeg = ToolLocator.LocateTool("ffmpeg.exe")?.ToWindowsPath() ?? throw new AssetException("Failed to compile a sound asset, ffmpeg was not found."); // Get absolute path of asset source on disk var assetDirectory = Parameters.Source.GetParent(); var assetSource = UPath.Combine(assetDirectory, Parameters.Source); // Execute ffmpeg to convert source to PCM and then encode with Celt var tempFile = Path.GetTempFileName(); try { var channels = Parameters.Spatialized ? 1 : 2; var commandLine = " -hide_banner -loglevel error" + // hide most log output $" -i \"{assetSource.ToWindowsPath()}\"" + // input file $" -f f32le -acodec pcm_f32le -ac {channels} -ar {Parameters.SampleRate}" + // codec $" -map 0:{Parameters.Index}" + // stream index $" -y \"{tempFile}\""; // output file (always overwrite) var ret = await ShellHelper.RunProcessAndGetOutputAsync(ffmpeg, commandLine, commandContext.Logger); if (ret != 0 || commandContext.Logger.HasErrors) { throw new AssetException($"Failed to compile a sound asset, ffmpeg failed to convert {assetSource}"); } var encoder = new Celt(Parameters.SampleRate, CompressedSoundSource.SamplesPerFrame, channels, false); var uncompressed = CompressedSoundSource.SamplesPerFrame * channels * sizeof(short); //compare with int16 for CD quality comparison.. but remember we are dealing with 32 bit floats for encoding!! var target = (int)Math.Floor(uncompressed / (float)Parameters.CompressionRatio); var dataUrl = Url + "_Data"; var newSound = new Sound { CompressedDataUrl = dataUrl, Channels = channels, SampleRate = Parameters.SampleRate, StreamFromDisk = Parameters.StreamFromDisk, Spatialized = Parameters.Spatialized, }; //make sure we don't compress celt data commandContext.AddTag(new ObjectUrl(UrlType.Content, dataUrl), Builder.DoNotCompressTag); var delay = encoder.GetDecoderSampleDelay(); var frameSize = CompressedSoundSource.SamplesPerFrame * channels; using (var reader = new BinaryReader(new FileStream(tempFile, FileMode.Open, FileAccess.Read))) using (var outputStream = MicrothreadLocalDatabases.DatabaseFileProvider.OpenStream(dataUrl, VirtualFileMode.Create, VirtualFileAccess.Write, VirtualFileShare.Read, StreamFlags.Seekable)) { var writer = new BinarySerializationWriter(outputStream); var outputBuffer = new byte[target]; var buffer = new float[frameSize]; var count = 0; var padding = sizeof(float) * channels * delay; var length = reader.BaseStream.Length; // Cache the length, because this getter is expensive to use for (var position = 0; position < length + padding; position += sizeof(float)) { if (count == frameSize) //flush { var len = encoder.Encode(buffer, outputBuffer); writer.Write((short)len); outputStream.Write(outputBuffer, 0, len); newSound.Samples += count / channels; newSound.NumberOfPackets++; newSound.MaxPacketLength = Math.Max(newSound.MaxPacketLength, len); count = 0; Array.Clear(buffer, 0, frameSize); } // Pad with 0 once we reach end of stream (this is needed because of encoding delay) buffer[count++] = (position < length) ? reader.ReadSingle() : 0.0f; } if (count > 0) //flush { var len = encoder.Encode(buffer, outputBuffer); writer.Write((short)len); outputStream.Write(outputBuffer, 0, len); newSound.Samples += count / channels; newSound.NumberOfPackets++; newSound.MaxPacketLength = Math.Max(newSound.MaxPacketLength, len); } } // Samples is the real sound sample count, remove the delay at the end newSound.Samples -= delay; var assetManager = new ContentManager(MicrothreadLocalDatabases.ProviderService); assetManager.Save(Url, newSound); return(ResultStatus.Successful); } finally { File.Delete(tempFile); } }
private void EncodeAudio(FusedSong song) { string mapPath = GetFilePath("hashes.json"); // Imports existing mappings if found AudioHashMappings audioMap = File.Exists(mapPath) ? AudioHashMappings.Import(mapPath) : new AudioHashMappings(); string GetPackageFilePath(string relativePath) => Path.Combine(_packageManager.CurrentPackageDirectory + "\\songs\\", song.Identifier.Replace(".", "\\") + "\\" + relativePath); bool IsCeltFile(string path) { string ext = Path.GetExtension(path); return(ext.Equals(".clt", StringComparison.CurrentCultureIgnoreCase)); } HashMapping EncodeAudio(string input, string output, HashMapping oldMap) { if (!File.Exists(input)) { // Delete if no input if (File.Exists(output)) { File.Delete(output); } return(oldMap); } else if (!File.Exists(output)) { // Encodes audio (Import from celt supported) Celt celt = IsCeltFile(input) ? Celt.FromFile(input) : Celt.FromAudio(input); celt.Export(output); // Updates hashes return(HashMapping.CreateMapping(input, output)); } HashMapping newMap = HashMapping.CreateMapping(input, output); if (newMap.Input != oldMap.Input || newMap.Output != oldMap.Output) { // Encodes audio Celt celt = IsCeltFile(input) ? Celt.FromFile(input) : Celt.FromAudio(input); celt.Export(output); // Updates output hash newMap.Output = HashMapping.ComputeHashFromFile(output); } // Else means they're equal, no need to re-encode // Returns new hashes return(newMap); } audioMap.Preview = EncodeAudio(GetFilePath(song.AudioPaths.Preview), GetPackageFilePath("preview\\audio.clt"), audioMap.Preview); audioMap.Backing = EncodeAudio(GetFilePath(song.AudioPaths.Backing), GetPackageFilePath("gamestems\\back\\audio.clt"), audioMap.Backing); audioMap.Bass = EncodeAudio(GetFilePath(song.AudioPaths.Bass), GetPackageFilePath("gamestems\\bass\\audio.clt"), audioMap.Bass); audioMap.Drums = EncodeAudio(GetFilePath(song.AudioPaths.Drums), GetPackageFilePath("gamestems\\drums\\audio.clt"), audioMap.Drums); audioMap.LeadGuitar = EncodeAudio(GetFilePath(song.AudioPaths.LeadGuitar), GetPackageFilePath("gamestems\\gtr1\\audio.clt"), audioMap.LeadGuitar); audioMap.RhythmGuitar = EncodeAudio(GetFilePath(song.AudioPaths.RhythmGuitar), GetPackageFilePath("gamestems\\gtr2\\audio.clt"), audioMap.RhythmGuitar); audioMap.Vox = EncodeAudio(GetFilePath(song.AudioPaths.Vox), GetPackageFilePath("gamestems\\vox\\audio.clt"), audioMap.Vox); audioMap.Export(mapPath); }