Exemple #1
0
        public Task WriteFileAsync(PCM16Audio lwav, string output_dir, string original_filename_no_ext)
        {
            Task t = new Task(() => WriteFile(lwav, output_dir, original_filename_no_ext));

            t.Start();
            return(t);
        }
Exemple #2
0
        public async Task WriteFileAsync(PCM16Audio lwav, string output_dir, string original_filename_no_ext)
        {
            string outPath = Path.Combine(output_dir, original_filename_no_ext + (Adts ? ".aac" : ".m4a"));

            if (outPath.Contains("\""))
            {
                throw new AudioExporterException("Invalid character (\") found in output filename");
            }

            string infile = TempFiles.Create("wav");

            File.WriteAllBytes(infile, lwav.Export());

            ProcessStartInfo psi = new ProcessStartInfo {
                FileName        = ExePath,
                UseShellExecute = false,
                CreateNoWindow  = true,
                Arguments       = $"--silent {(Adts ? "--adts " : "")} {EncodingParameters} {infile} -o \"{outPath}\""
            };
            var pr = await ProcessEx.RunAsync(psi);

            File.Delete(infile);

            if (pr.ExitCode != 0)
            {
                foreach (string s in pr.StandardError)
                {
                    Console.WriteLine(s);
                }
                throw new AudioExporterException("qaac quit with exit code " + pr.ExitCode);
            }
        }
Exemple #3
0
        public async Task WriteFileAsync(PCM16Audio lwav, string output_dir, string original_filename_no_ext)
        {
            string outPath = Path.Combine(output_dir, original_filename_no_ext + ".mp3");

            if (outPath.Contains("\""))
            {
                throw new AudioExporterException("Invalid character (\") found in output filename");
            }

            if (lwav.OriginalMP3 != null)
            {
                File.WriteAllBytes(outPath, lwav.OriginalMP3);
                return;
            }

            string infile = TempFiles.Create("wav");

            File.WriteAllBytes(infile, lwav.Export());

            ProcessStartInfo psi = new ProcessStartInfo {
                FileName        = ExePath,
                UseShellExecute = false,
                CreateNoWindow  = true,
                Arguments       = "--silent " + EncodingParameters + " " + infile + " \"" + outPath + "\""
            };
            var pr = await ProcessEx.RunAsync(psi);

            File.Delete(infile);

            if (pr.ExitCode != 0)
            {
                throw new AudioExporterException("LAME quit with exit code " + pr.ExitCode);
            }
        }
        public void WriteFile(PCM16Audio lwav, string output_dir, string original_filename_no_ext)
        {
            string outPath = Path.Combine(output_dir, original_filename_no_ext + ".mp3");

            if (outPath.Contains("\""))
            {
                throw new AudioExporterException("Invalid character (\") found in output filename");
            }

            string infile = TempFiles.Create("wav");

            File.WriteAllBytes(infile, lwav.Export());

            ProcessStartInfo psi = new ProcessStartInfo {
                FileName        = ExePath,
                UseShellExecute = false,
                CreateNoWindow  = true,
                Arguments       = "--silent " + EncodingParameters + " " + infile + " \"" + outPath + "\""
            };
            Process p = Process.Start(psi);

            p.WaitForExit();
            File.Delete(infile);

            if (p.ExitCode != 0)
            {
                throw new AudioExporterException("LAME quit with exit code " + p.ExitCode);
            }
        }
Exemple #5
0
        public Task WriteFileAsync(PCM16Audio lwav, string output_dir, string original_filename_no_ext)
        {
            string output_filename = Path.Combine(output_dir, original_filename_no_ext + ".wav");

            File.WriteAllBytes(output_filename, lwav.Export());
            return(Task.FromResult(0));
        }
Exemple #6
0
        public PCM16Audio ReadFile(string filename)
        {
            using (var fs = new FileStream(filename, FileMode.Open, FileAccess.Read))
                using (var br = new BinaryReader(fs)) {
                    foreach (char c in "MSU1")
                    {
                        byte x = br.ReadByte();
                        if (x != c)
                        {
                            throw new AudioImporterException("This is not a valid MSU-1 .pcm file");
                        }
                    }

                    uint loopStart = br.ReadUInt32();

                    short[] sampleData = new short[(fs.Length - 8) / sizeof(short)];
                    for (int i = 0; i < sampleData.Length; i++)
                    {
                        sampleData[i] = br.ReadInt16();
                    }

                    var pcm16 = new PCM16Audio(2, 44100, sampleData, checked ((int)loopStart));
                    if (loopStart == 0)
                    {
                        // This might be a non-looping song, or a song that loops without any lead-in.
                        pcm16.Looping    = false;
                        pcm16.NonLooping = false;
                    }
                    return(pcm16);
                }
        }
Exemple #7
0
        public void WriteFile(PCM16Audio lwav, string output_dir, string original_filename_no_ext)
        {
            string output_filename = Path.Combine(output_dir, original_filename_no_ext + ".pcm");

            using (var fs = new FileStream(output_filename, FileMode.Create, FileAccess.Write))
                using (var bw = new BinaryWriter(fs)) {
                    foreach (char c in "MSU1")
                    {
                        bw.Write((byte)c);
                    }

                    if (lwav.Looping)
                    {
                        bw.Write((int)lwav.LoopStart);
                    }
                    else
                    {
                        bw.Write((int)0);
                    }

                    foreach (short sample in lwav.Samples)
                    {
                        bw.Write(sample);
                    }
                }
        }
        /// <summary>
        /// Writes the LWAV to the given file, using SoX to make sure the format is correct. SoX can encode and write FLAC and Ogg Vorbis files, among others.
        /// </summary>
        /// <param name="lwav">Input audio</param>
        /// <param name="output_filename">Path of output file</param>
        public void WriteFile(PCM16Audio lwav, string output_filename, string encodingParameters = null)
        {
            if (output_filename.Contains('"'))
            {
                throw new AudioImporterException("File paths with double quote marks (\") are not supported");
            }

            string infile = TempFiles.Create("wav");

            File.WriteAllBytes(infile, lwav.Export());

            ProcessStartInfo psi = new ProcessStartInfo {
                FileName        = ExePath,
                Arguments       = infile + " " + (encodingParameters ?? "") + " \"" + output_filename + "\"",
                UseShellExecute = false,
                CreateNoWindow  = true
            };
            Process p = Process.Start(psi);

            p.WaitForExit();

            File.Delete(infile);

            if (p.ExitCode != 0)
            {
                throw new AudioExporterException("SoX quit with exit code " + p.ExitCode);
            }
        }
        /// <summary>
        /// Converts a file to WAV using SoX and reads it into an LWAV object.
        /// If the format is not supported, SoX will write a message to the console and this function will throw an AudioImporterException.
        /// </summary>
        /// <param name="filename">The path of the file to read</param>
        /// <returns>A non-looping LWAV</returns>
        public PCM16Audio ReadFile(string filename)
        {
            if (!File.Exists(ExePath))
            {
                throw new AudioImporterException("test.exe not found at path: " + ExePath);
            }
            if (filename.Contains('"'))
            {
                throw new AudioImporterException("File paths with double quote marks (\") are not supported");
            }

            string outfile = TempFiles.Create("wav");

            ProcessStartInfo psi = new ProcessStartInfo {
                FileName        = ExePath,
                UseShellExecute = false,
                CreateNoWindow  = true,
                Arguments       = "\"" + filename + "\" -b 16 -t wav " + outfile
            };
            Process p = Process.Start(psi);

            p.WaitForExit();

            try {
                PCM16Audio lwav = PCM16Factory.FromFile(outfile, true);
                return(lwav);
            } catch (Exception e) {
                throw new AudioImporterException("Could not read SoX output: " + e.Message);
            }
        }
Exemple #10
0
        public Task WriteFileAsync(PCM16Audio lwav, string output_dir, string original_filename_no_ext)
        {
            if (lwav.Channels != 2 || lwav.SampleRate != 44100)
            {
                throw new AudioExporterException("MSU-1 output must be 2-channel audio at a sample rate of 44100Hz.");
            }

            string output_filename = Path.Combine(output_dir, original_filename_no_ext + ".pcm");

            using (var fs = new FileStream(output_filename, FileMode.Create, FileAccess.Write))
                using (var bw = new BinaryWriter(fs)) {
                    foreach (char c in "MSU1")
                    {
                        bw.Write((byte)c);
                    }

                    if (lwav.Looping)
                    {
                        bw.Write((int)lwav.LoopStart);
                    }
                    else
                    {
                        bw.Write((int)0);
                    }

                    foreach (short sample in lwav.Samples)
                    {
                        bw.Write(sample);
                    }
                }
            return(Task.FromResult(0));
        }
Exemple #11
0
        /// <summary>
        /// Converts a file to WAV using test.exe and reads it into a PCM16Audio object.
        /// If the format is not supported, test.exe will write a message to the console and this function will throw an AudioImporterException.
        /// </summary>
        /// <param name="filename">The path of the file to read</param>
        /// <returns>A PCM16Audio, which may or may not be looping</returns>
        public async Task <PCM16Audio> ReadFileAsync(string filename)
        {
            if (!File.Exists(TestExePath))
            {
                throw new AudioImporterException("test.exe not found at path: " + TestExePath);
            }
            if (filename.Contains('"'))
            {
                throw new AudioImporterException("File paths with double quote marks (\") are not supported");
            }

            if (!Directory.Exists("tmp"))
            {
                Directory.CreateDirectory("tmp");
            }

            ProcessStartInfo psi = new ProcessStartInfo {
                WorkingDirectory = "tmp",
                FileName         = TestExePath,
                UseShellExecute  = false,
                CreateNoWindow   = true,
                Arguments        = "-L -l 1 -f 0 -o dump.wav \"" + filename + "\""
            };
            var pr = await ProcessEx.RunAsync(psi);

            try {
                PCM16Audio lwav = PCM16Factory.FromFile("tmp/dump.wav", true);
                return(lwav);
            } catch (Exception e) {
                throw new AudioImporterException("Could not read output of test.exe: " + e.Message);
            }
        }
Exemple #12
0
        public void WriteFile(PCM16Audio lwav, string output_dir, string original_filename_no_ext)
        {
            AudioData audio = lwav.OriginalAudioData ?? new WaveReader().Read(lwav.Export());

            audio.SetLoop(lwav.Looping, lwav.LoopStart, lwav.LoopEnd);
            byte[] data = GetData(audio);
            File.WriteAllBytes(Path.Combine(output_dir, original_filename_no_ext + GetExtension()), data);
        }
Exemple #13
0
        public Task WriteFileAsync(PCM16Audio lwav, string output_dir, string original_filename_no_ext)
        {
            var    msf     = MSF.FromAudioSource(lwav, big_endian: big_endian);
            string outPath = Path.Combine(output_dir, original_filename_no_ext + ".msf");

            File.WriteAllBytes(outPath, msf.Export());
            return(Task.CompletedTask);
        }
Exemple #14
0
        public void WriteFile(PCM16Audio lwav, string output_dir, string original_filename_no_ext)
        {
            string output_filename = Path.Combine(output_dir, original_filename_no_ext + ".ogg");

            // Don't re-encode if the original input file was also Ogg Vorbis
            if (lwav.OriginalPath != null && new string[] { ".ogg", ".logg" }.Contains(Path.GetExtension(lwav.OriginalPath), StringComparer.InvariantCultureIgnoreCase))
            {
                File.Copy(lwav.OriginalPath, output_filename, true);
            }
            else
            {
                sox.WriteFile(lwav, output_filename, encodingParameters);
            }

            using (VorbisFile file = new VorbisFile(File.ReadAllBytes(output_filename))) {
                var commentHeader = file.GetPageHeaders().Select(p => p.GetCommentHeader()).Where(h => h != null).FirstOrDefault();
                var comments      = commentHeader?.ExtractComments() ?? new VorbisComments();
                if (lwav.Looping)
                {
                    if (commentHeader == null)
                    {
                        throw new Exception("No comment header found in Ogg Vorbis file - cannot edit it to make it loop.");
                    }

                    string loopStart  = null;
                    string loopLength = null;
                    comments.Comments.TryGetValue("LOOPSTART", out loopStart);
                    comments.Comments.TryGetValue("LOOPLENGTH", out loopLength);

                    if (loopStart != lwav.LoopStart.ToString() || loopLength != lwav.LoopLength.ToString())
                    {
                        comments.Comments["LOOPSTART"]  = lwav.LoopStart.ToString();
                        comments.Comments["LOOPLENGTH"] = lwav.LoopLength.ToString();
                        using (VorbisFile newFile = new VorbisFile(file, comments)) {
                            File.WriteAllBytes(output_filename, newFile.ToByteArray());
                        }
                    }
                }
                else
                {
                    if (comments.Comments.ContainsKey("LOOPSTART") || comments.Comments.ContainsKey("LOOPLENGTH"))
                    {
                        comments.Comments.Remove("LOOPSTART");
                        comments.Comments.Remove("LOOPLENGTH");
                        using (VorbisFile newFile = new VorbisFile(file, comments)) {
                            File.WriteAllBytes(output_filename, newFile.ToByteArray());
                        }
                    }
                }
            }
        }
Exemple #15
0
        public void WriteFile(PCM16Audio lwav, string output_dir, string original_filename_no_ext)
        {
            string output_filename = Path.Combine(output_dir, original_filename_no_ext + ".wav");
            int    length          = lwav.Samples.Length / lwav.Channels;
            string filename        = Path.GetFileNameWithoutExtension(lwav.OriginalPath);

            if (lwav.Looping)
            {
                if (!txt.Contains(filename))
                {
                    txt += $"{lwav.LoopStart} {lwav.LoopEnd} {lwav.Samples.Length / lwav.Channels} {Path.GetFileNameWithoutExtension(lwav.OriginalPath)}.wav\r\n";
                }
            }
            File.WriteAllBytes(output_filename, lwav.Export());
        }
Exemple #16
0
 public Task <PCM16Audio> ReadFileAsync(string filename)
 {
     byte[] data = File.ReadAllBytes(filename);
     try {
         IPcmAudioSource <short> msf = MSF.Parse(data);
         var lwav = new PCM16Audio(
             msf.Channels,
             msf.SampleRate,
             msf.SampleData.ToArray(),
             msf.LoopStartSample,
             msf.LoopStartSample + msf.LoopSampleCount,
             !msf.IsLooping);
         if (msf is MSF_MP3 mp3)
         {
             lwav.OriginalMP3 = mp3.Body;
         }
         return(Task.FromResult(lwav));
     } catch (NotSupportedException) {
         throw new AudioImporterException("Cannot read MSF file (unsupported codec?)");
     }
 }
Exemple #17
0
 public PCM16LoopWrapper(PCM16Audio lwav)
 {
     this.lwav = lwav;
 }
Exemple #18
0
        /// <summary>
        /// Runs a batch conversion process.
        /// </summary>
        /// <param name="o">Options for the batch.</param>
        public static void Run(Options o, bool showEndDialog = true)
        {
            if (o.ExporterType == ExporterType.MP3 && (o.ExportPreLoop || o.ExportLoop))
            {
                MessageBox.Show("MP3 encoding adds gaps at the start and end of each file, so the before-loop portion and the loop portion will not line up well.",
                                "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }

            SoX sox = new SoX(ConfigurationManager.AppSettings["sox_path"]);

            WAVExporter.txt = "";

            List <IAudioImporter> importers = new List <IAudioImporter> {
                new WAVImporter(),
                new MP3Importer(ConfigurationManager.AppSettings["madplay_path"]),
                new MP4Importer(ConfigurationManager.AppSettings["faad_path"]),
                new VGMImporter(ConfigurationManager.AppSettings["vgmplay_path"] ?? ConfigurationManager.AppSettings["vgm2wav_path"]),
                new MSU1(),
                new VGMStreamImporter(ConfigurationManager.AppSettings["vgmstream_path"]),
                sox
            };

            if (o.VGAudioDecoder)
            {
                importers.Insert(1, new VGAudioImporter());
            }

            IAudioExporter exporter;

            switch (o.ExporterType)
            {
            case ExporterType.BRSTM:
                exporter = new RSTMExporter(o.BxstmCodec);
                break;

            case ExporterType.BCSTM:
                exporter = new CSTMExporter(o.BxstmCodec);
                break;

            case ExporterType.BFSTM_Cafe:
                exporter = new FSTMExporter(o.BxstmCodec, NwTarget.Cafe);
                break;

            case ExporterType.BFSTM_NX:
                exporter = new FSTMExporter(o.BxstmCodec, NwTarget.NX);
                break;

            case ExporterType.DSP:
                exporter = new DSPExporter();
                break;

            case ExporterType.IDSP:
                exporter = new IDSPExporter();
                break;

            case ExporterType.HCA:
                exporter = new HCAExporter();
                break;

            case ExporterType.HPS:
                exporter = new HPSExporter();
                break;

            case ExporterType.BRSTM_BrawlLib:
                exporter = new Brawl.RSTMExporter();
                break;

            case ExporterType.BCSTM_BrawlLib:
                exporter = new Brawl.CSTMExporter();
                break;

            case ExporterType.BFSTM_BrawlLib:
                exporter = new Brawl.FSTMExporter();
                break;

            case ExporterType.MSU1:
                exporter = new MSU1();
                break;

            case ExporterType.FLAC:
                exporter = new FLACExporter(sox);
                break;

            case ExporterType.MP3:
                exporter = new MP3Exporter(ConfigurationManager.AppSettings["lame_path"], o.MP3EncodingParameters);
                break;

            case ExporterType.AAC_M4A:
                exporter = new AACExporter(ConfigurationManager.AppSettings["qaac_path"], o.AACEncodingParameters, adts: false);
                break;

            case ExporterType.AAC_ADTS:
                exporter = new AACExporter(ConfigurationManager.AppSettings["qaac_path"], o.AACEncodingParameters, adts: true);
                break;

            case ExporterType.OggVorbis:
                exporter = new OggVorbisExporter(sox, o.OggVorbisEncodingParameters);
                break;

            case ExporterType.WAV:
                exporter = new WAVExporter();
                break;

            default:
                throw new Exception("Could not create exporter type " + o.ExporterType);
            }

            List <Task> tasks = new List <Task>();
            Semaphore   sem   = new Semaphore(o.NumSimulTasks, o.NumSimulTasks);

            MultipleProgressWindow window = new MultipleProgressWindow();

            new Thread(new ThreadStart(() => {
                Application.EnableVisualStyles();
                window.ShowDialog();
            })).Start();

            Dictionary <string, Tuple <int, int, int> > loopOverrides = new Dictionary <string, Tuple <int, int, int> >();

            if (File.Exists("loop.txt"))
            {
                using (StreamReader sr = new StreamReader("loop.txt")) {
                    string line;
                    while ((line = sr.ReadLine()) != null)
                    {
                        line = Regex.Replace(line, "[ \t]+", " ");
                        if (line.Length > 0 && line[0] != '#' && line.Contains(' '))
                        {
                            try {
                                int loopStart = int.Parse(line.Substring(0, line.IndexOf(" ")));
                                line = line.Substring(line.IndexOf(" ") + 1);
                                int loopEnd = int.Parse(line.Substring(0, line.IndexOf(" ")));
                                line = line.Substring(line.IndexOf(" ") + 1);
                                int samplerate = int.Parse(line.Substring(0, line.IndexOf(" ")));
                                line = line.Substring(line.IndexOf(" ") + 1);

                                loopOverrides.Add(line, new Tuple <int, int, int>(loopStart, loopEnd, samplerate));
                            } catch (Exception e) {
                                Console.Error.WriteLine("Could not parse line in loop.txt: " + line + " - " + e.Message);
                            }
                        }
                    }
                }
            }

            if (!o.InputFiles.Any())
            {
                MessageBox.Show("No input files were selected.");
            }

            int   i           = 0;
            float maxProgress = o.InputFiles.Count() * 2;

            List <string> exported = new List <string>();
            DateTime      start    = DateTime.UtcNow;

            foreach (string inputFile in o.InputFiles)
            {
                sem.WaitOne();
                if (window.Canceled)
                {
                    break;
                }

                string outputDir = o.OutputDir;
                string inputDir  = Path.GetDirectoryName(inputFile);
                for (int x = 0; x < 100; x++)
                {
                    int index = outputDir.LastIndexOf('*');
                    if (index < 0)
                    {
                        break;
                    }

                    string replacement = Path.GetFileName(inputDir);
                    outputDir = outputDir.Substring(0, index) + replacement + outputDir.Substring(index + 1);
                    inputDir  = Path.GetDirectoryName(inputDir);
                }

                if (!Directory.Exists(outputDir))
                {
                    try {
                        Directory.CreateDirectory(outputDir);
                    } catch (Exception e) {
                        MessageBox.Show("Could not create output directory " + o.OutputDir + ": " + e.Message);
                    }
                }

                string filename_no_ext = Path.GetFileNameWithoutExtension(inputFile);
                window.SetDecodingText(filename_no_ext);

                string extension = Path.GetExtension(inputFile);

                PCM16Audio w = null;
                List <AudioImporterException> exceptions = new List <AudioImporterException>();

                var importers_supported = importers.Where(im => im.SupportsExtension(extension));
                if (!importers_supported.Any())
                {
                    throw new Exception("No importers supported for file extension " + extension);
                }

                foreach (IAudioImporter importer in importers_supported)
                {
                    try {
                        Console.WriteLine("Decoding " + Path.GetFileName(inputFile) + " with " + importer.GetImporterName());
                        if (importer is IRenderingAudioImporter)
                        {
                            ((IRenderingAudioImporter)importer).SampleRate = o.MaxSampleRate;
                        }
                        w = importer.ReadFile(inputFile);
                        w.OriginalPath = inputFile;
                        break;
                    } catch (AudioImporterException e) {
                        //Console.Error.WriteLine(importer.GetImporterName() + " could not read file " + inputFile + ": " + e.Message);
                        exceptions.Add(e);
                    }
                }

                if (loopOverrides.Any())
                {
                    if (loopOverrides.TryGetValue(Path.GetFileName(inputFile), out Tuple <int, int, int> val))
                    {
                        if (val.Item1 < 0)
                        {
                            w.Looping = false;
                        }
                        else
                        {
                            w.Looping   = true;
                            w.LoopStart = (int)((float)val.Item1 / val.Item3 * (w.Samples.Length / w.Channels));                             // use floats for division accuracy, then round back
                            w.LoopEnd   = (int)((float)val.Item2 / val.Item3 * (w.Samples.Length / w.Channels));
                        }
                    }
                }

                if (w == null)
                {
                    window.SetDecodingText("");
                    DialogResult dr = MessageBox.Show("Could not read " + inputFile + ".", "Error", MessageBoxButtons.OKCancel, MessageBoxIcon.Error);
                    if (dr == DialogResult.Cancel)
                    {
                        break;
                    }
                    else
                    {
                        continue;
                    }
                }

                window.SetDecodingText(filename_no_ext + " (applying effects)");
                w = sox.ApplyEffects(w,
                                     max_channels: o.MaxChannels ?? int.MaxValue,
                                     max_rate: o.MaxSampleRate ?? int.MaxValue,
                                     db: o.AmplifydB ?? 0M,
                                     amplitude: o.AmplifyRatio ?? 1M);
                window.SetDecodingText("");

                List <NamedAudio> wavsToExport = new List <NamedAudio>();

                if (o.ExportWholeSong)
                {
                    wavsToExport.Add(new NamedAudio(w.PlayLoopAndFade(o.NumberOfLoops, o.FadeOutSec), filename_no_ext + o.WholeSongSuffix));
                }
                if (o.ExportPreLoop)
                {
                    wavsToExport.Add(new NamedAudio(w.GetPreLoopSegment(), filename_no_ext + o.PreLoopSuffix));
                }
                if (o.ExportLoop)
                {
                    wavsToExport.Add(new NamedAudio(w.GetLoopSegment(), filename_no_ext + o.LoopSuffix));
                }

                if (o.ChannelSplit == ChannelSplit.Pairs)
                {
                    wavsToExport = wavsToExport.SelectMany(x => x.SplitMultiChannelToStereo()).ToList();
                }
                if (o.ChannelSplit == ChannelSplit.Each)
                {
                    wavsToExport = wavsToExport.SelectMany(x => x.SplitMultiChannelToMono()).ToList();
                }

                sem.Release();

                foreach (NamedAudio n in wavsToExport)
                {
                    NamedAudio toExport = n;
                    int        claims   = 1;
                    if (exporter is VGAudioExporter)
                    {
                        // VGAudio runs tasks in parallel for each channel, so let's consider that when deciding how many tasks to run.
                        claims = Math.Min(n.LWAV.Channels, o.NumSimulTasks);
                    }
                    for (int j = 0; j < claims; j++)
                    {
                        sem.WaitOne();
                    }
                    switch (o.UnknownLoopBehavior)
                    {
                    case UnknownLoopBehavior.ForceLoop:
                        if (!toExport.LWAV.Looping && !toExport.LWAV.NonLooping)
                        {
                            toExport.LWAV.Looping   = true;
                            toExport.LWAV.LoopStart = 0;
                            toExport.LWAV.LoopEnd   = toExport.LWAV.Samples.Length / toExport.LWAV.Channels;
                        }
                        break;

                    case UnknownLoopBehavior.Ask:
                    case UnknownLoopBehavior.AskAll:
                        if (toExport.LWAV.Looping || toExport.LWAV.NonLooping)
                        {
                            if (o.UnknownLoopBehavior != UnknownLoopBehavior.AskAll)
                            {
                                break;
                            }
                        }
                        PCM16LoopWrapper audioStream = new PCM16LoopWrapper(toExport.LWAV);
                        using (BrstmConverterDialog dialog = new BrstmConverterDialog(audioStream)) {
                            dialog.AudioSource = n.Name;
                            if (dialog.ShowDialog() != DialogResult.OK)
                            {
                                toExport = null;
                            }
                        }
                        break;
                    }
                    if (toExport == null)
                    {
                        i++;
                        break;
                    }

                    if (!o.ShortCircuit)
                    {
                        if (toExport.LWAV.OriginalPath != null)
                        {
                            toExport.LWAV.OriginalPath = null;
                        }
                        if (toExport.LWAV.OriginalAudioData != null)
                        {
                            toExport.LWAV.OriginalAudioData = null;
                        }
                    }
                    if (!o.WriteLoopingMetadata)
                    {
                        toExport.LWAV.Looping = false;
                    }

                    var row = window.AddEncodingRow(toExport.Name);
                    //if (o.NumSimulTasks == 1) {
                    //    exporter.WriteFile(toExport.LWAV, outputDir, toExport.Name);
                    //    lock (exported) {
                    //        exported.Add(toExport.Name);
                    //    }
                    //    for (int j = 0; j < claims; j++) {
                    //        sem.Release();
                    //    }
                    //    row.Remove();
                    //} else {
                    Task task = new Task(() => exporter.WriteFile(toExport.LWAV, outputDir, toExport.Name));
                    task.Start();
                    tasks.Add(task);
                    tasks.Add(task.ContinueWith(t => {
                        lock (exported) {
                            exported.Add(toExport.Name);
                        }
                        for (int j = 0; j < claims; j++)
                        {
                            sem.Release();
                        }
                        row.Remove();
                    }));
                    //}
                }
            }
            foreach (var t in tasks)
            {
                try {
                    t.Wait();
                } catch (Exception ex) {
                    Console.Error.WriteLine($"{ex.GetType()}: {ex.Message}");
                    Console.Error.WriteLine(ex.StackTrace);
                    MessageBox.Show((ex.InnerException ?? ex).Message);
                }
            }
            DateTime end = DateTime.UtcNow;

            if (window.Visible)
            {
                window.BeginInvoke(new Action(() => {
                    window.AllowClose = true;
                    window.Close();
                }));
            }

            File.WriteAllText("./inloop.txt", WAVExporter.txt);

            if (showEndDialog)
            {
                MessageBox.Show("Exported " + exported.Count + " file(s), total time: " + (end - start));
            }
        }
        /// <summary>
        /// Applies one or more SoX effects to the LWAV given and reads the result into a new LWAV.
        /// Intended to either adjust the volume of the audio or reduce the file size.
        /// </summary>
        /// <param name="lwav">The LWAV to use as an input</param>
        /// <param name="max_channels">The new number of channels (if the LWAV already has this number of channels or fewer, this effect will not be applied)</param>
        /// <param name="db">Volume adjustment, in decibels (if 0, this effect will not be applied)</param>
        /// <param name="amplitude">Volume adjustment, in linear ratio (if 1, this effect will not be applied)</param>
        /// <param name="max_rate">The new sample rate (if the LWAV's sample rate is less than or equal to this value, this effect will not be applied)</param>
        /// <returns>A new LWAV object if one or more effects are applied; the same LWAV object if no effects are applied.</returns>
        public PCM16Audio ApplyEffects(PCM16Audio lwav, int max_channels = int.MaxValue, decimal db = 0, decimal amplitude = 1, int max_rate = int.MaxValue)
        {
            byte[] wav = lwav.Export();

            int channels   = Math.Min(max_channels, lwav.Channels);
            int sampleRate = Math.Min(max_rate, lwav.SampleRate);

            StringBuilder effects_string = new StringBuilder();

            if (channels != lwav.Channels)
            {
                effects_string.Append(" channels " + max_channels);
            }
            if (db != 0)
            {
                effects_string.Append(" vol " + db + " dB");
            }
            if (amplitude != 1)
            {
                effects_string.Append(" vol " + amplitude + " amplitude");
            }
            if (sampleRate != lwav.SampleRate)
            {
                effects_string.Append(" rate " + max_rate);
            }

            if (effects_string.Length == 0)
            {
                // No effects will be performed - just return the same LWAV that was passed in without calling SoX unnecessarily
                return(lwav);
            }

            string infile  = TempFiles.Create("wav");
            string outfile = TempFiles.Create("wav");

            File.WriteAllBytes(infile, wav);

            // Sometimes when SoX changes sample rate and sends the result to stdout, it gives the wrong length in the data chunk. Let's just have it send us raw PCM data instead.
            ProcessStartInfo psi = new ProcessStartInfo {
                FileName        = ExePath,
                UseShellExecute = false,
                CreateNoWindow  = true,
                Arguments       = "-t wav " + infile + " -t wav " + outfile + " " + effects_string
            };
            Process p = Process.Start(psi);

            p.WaitForExit();
            File.Delete(infile);

            try {
                PCM16Audio l = PCM16Factory.FromFile(outfile, true);
                l.Looping   = lwav.Looping;
                l.LoopStart = lwav.LoopStart;
                l.LoopEnd   = lwav.LoopEnd;

                if (l.Looping && l.SampleRate != lwav.SampleRate)
                {
                    // When the sample rate is changed, we need to change the loop points to match.
                    double ratio = (double)l.SampleRate / lwav.SampleRate;
                    l.LoopStart = (int)(l.LoopStart * ratio);
                    l.LoopEnd   = (int)(l.LoopEnd * ratio);
                }
                return(l);
            } catch (Exception e) {
                throw new AudioImporterException("Could not read SoX output: " + e.Message);
            }
        }
Exemple #20
0
 public async Task WriteFileAsync(PCM16Audio lwav, string output_dir, string original_filename_no_ext)
 {
     await sox.WriteFileAsync(lwav, Path.Combine(output_dir, original_filename_no_ext + ".flac"));
 }
Exemple #21
0
        /// <summary>
        /// Reads RIFF WAVE data from a stream.
        /// If the size of the "data" chunk is incorrect or negative, but the "data" chunk is known to be the last chunk in the file, set the assumeDataIsLastChunk parameter to true.
        /// </summary>
        /// <param name="stream">Stream to read from (no data will be written to the stream)</param>
        /// <returns></returns>
        public unsafe static PCM16Audio FromStream(Stream stream)
        {
            byte[] buffer = new byte[12];
            int    r      = stream.Read(buffer, 0, 12);

            if (r == 0)
            {
                throw new PCM16FactoryException("No data in stream");
            }
            else if (r < 12)
            {
                throw new PCM16FactoryException("Unexpected end of stream in first 12 bytes");
            }

            fixed(byte *bptr = buffer)
            {
                if (*(int *)bptr != tag("RIFF"))
                {
                    throw new PCM16FactoryException("RIFF header not found");
                }
                if (*(int *)(bptr + 8) != tag("WAVE"))
                {
                    throw new PCM16FactoryException("WAVE header not found");
                }
            }

            int channels   = 0;
            int sampleRate = 0;

            short[] sample_data        = null;
            bool    convert_from_8_bit = false;

            int?loopStart = null;
            int?loopEnd   = null;

            // Keep reading chunk headers into a buffer of 8 bytes
            while ((r = stream.Read(buffer, 0, 8)) > 0)
            {
                if (r < 8)
                {
                    throw new PCM16FactoryException("Unexpected end of stream in chunk header");
                }
                else
                {
                    fixed(byte *ptr1 = buffer)
                    {
                        // Four ASCII characters
                        string id = Marshal.PtrToStringAnsi((IntPtr)ptr1, 4);

                        int chunklength = *(int *)(ptr1 + 4);

                        byte[] buffer2;
                        if (id == "data" && chunklength == -1)
                        {
                            // Special handling for streaming output of madplay.exe.
                            // If we were using temporary files, this would not be needed, but I like a good programming challenge.
                            using (MemoryStream ms = new MemoryStream()) {
                                byte[] databuffer = new byte[1024 * 1024];
                                while ((r = stream.Read(databuffer, 0, databuffer.Length)) > 0)
                                {
                                    ms.Write(databuffer, 0, r);
                                }

                                buffer2 = ms.ToArray();
                            }
                        }
                        else
                        {
                            // Look at the length of the chunk and read that many bytes into a byte array.
                            buffer2 = new byte[chunklength];
                            int total = 0;
                            while (total < buffer2.Length)
                            {
                                total += (r = stream.Read(buffer2, total, buffer2.Length - total));
                                if (r == 0)
                                {
                                    throw new PCM16FactoryException("Unexpected end of data in \"" + Marshal.PtrToStringAnsi((IntPtr)ptr1, 4) + "\" chunk: expected " + buffer2.Length + " bytes, got " + total + " bytes");
                                }
                            }
                        }

                        fixed(byte *ptr2 = buffer2)
                        {
                            if (id == "fmt ")
                            {
                                // Format chunk
                                fmt *fmt = (fmt *)ptr2;
                                if (fmt->format != 1)
                                {
                                    if (fmt->format == 65534)
                                    {
                                        // WAVEFORMATEXTENSIBLE
                                        fmt_extensible *ext = (fmt_extensible *)fmt;
                                        if (ext->subFormat == new Guid("00000001-0000-0010-8000-00aa00389b71"))
                                        {
                                            // KSDATAFORMAT_SUBTYPE_PCM
                                        }
                                        else
                                        {
                                            throw new PCM16FactoryException("Only uncompressed PCM suppported - found WAVEFORMATEXTENSIBLE with subformat " + ext->subFormat);
                                        }
                                    }
                                    else
                                    {
                                        throw new PCM16FactoryException("Only uncompressed PCM suppported - found format " + fmt->format);
                                    }
                                }
                                else if (fmt->bitsPerSample != 16)
                                {
                                    if (fmt->bitsPerSample == 8)
                                    {
                                        convert_from_8_bit = true;
                                    }
                                    else
                                    {
                                        throw new PCM16FactoryException("Only 16-bit wave files supported");
                                    }
                                }

                                channels   = fmt->channels;
                                sampleRate = fmt->sampleRate;
                            }
                            else if (id == "data")
                            {
                                // Data chunk - contains samples
                                sample_data = new short[buffer2.Length / 2];
                                Marshal.Copy((IntPtr)ptr2, sample_data, 0, sample_data.Length);
                            }
                            else if (id == "smpl")
                            {
                                // sampler chunk
                                smpl *smpl = (smpl *)ptr2;
                                if (smpl->sampleLoopCount > 1)
                                {
                                    throw new PCM16FactoryException("Cannot read looping .wav file with more than one loop");
                                }
                                else if (smpl->sampleLoopCount == 1)
                                {
                                    // There is one loop - we only care about start and end points
                                    smpl_loop *loop = (smpl_loop *)(smpl + 1);
                                    if (loop->type != 0)
                                    {
                                        throw new PCM16FactoryException("Cannot read looping .wav file with loop of type " + loop->type);
                                    }
                                    loopStart = loop->start;
                                    loopEnd   = loop->end;
                                }
                            }
                            else
                            {
                                Console.Error.WriteLine("Ignoring unknown chunk " + id);
                            }
                        }
                    }
                }
            }

            if (sampleRate == 0)
            {
                throw new PCM16FactoryException("Format chunk not found");
            }
            if (sample_data == null)
            {
                throw new PCM16FactoryException("Data chunk not found");
            }

            if (convert_from_8_bit)
            {
                short[] new_sample_data = new short[sample_data.Length * 2];
                fixed(short *short_ptr = sample_data)
                {
                    byte *ptr = (byte *)short_ptr;

                    for (int i = 0; i < new_sample_data.Length; i++)
                    {
                        new_sample_data[i] = (short)((ptr[i] - 0x80) << 8);
                    }
                }

                sample_data = new_sample_data;
            }

            PCM16Audio wav = new PCM16Audio(channels, sampleRate, sample_data, loopStart, loopEnd);

            return(wav);
        }
Exemple #22
0
 public void WriteFile(PCM16Audio lwav, string output_dir, string original_filename_no_ext)
 {
 }
Exemple #23
0
        /// <summary>
        /// Exports data to a byte array in RIFF WAVE (.wav) format.
        /// Output data will use WAVE_FORMAT_PCM and have "fmt " and "data" chunks, along with a "smpl" chunk if it is a looping track.
        /// Note that even files with more than 2 channels will use WAVE_FORMAT_PCM as the format, even though doing this is invalid according to the spec.
        /// </summary>
        /// <param name="lwav"></param>
        /// <returns></returns>
        public static unsafe byte[] Export(this PCM16Audio lwav)
        {
            int length = 12 + 8 + sizeof(fmt) + 8 + (lwav.Samples.Length * 2);

            if (lwav.Looping)
            {
                length += 8 + sizeof(smpl) + sizeof(smpl_loop);
            }
            byte[] data = new byte[length];
            fixed(byte *start = data)
            {
                byte *ptr = start;

                *(int *)ptr = tag("RIFF");
                ptr        += 4;
                *(int *)ptr = length - 8;
                ptr        += 4;
                *(int *)ptr = tag("WAVE");
                ptr        += 4;

                *(int *)ptr = tag("fmt ");
                ptr        += 4;
                *(int *)ptr = sizeof(fmt);
                ptr        += 4;

                fmt *fmt = (fmt *)ptr;

                fmt->format        = 1;
                fmt->channels      = lwav.Channels;
                fmt->sampleRate    = lwav.SampleRate;
                fmt->byteRate      = lwav.SampleRate * lwav.Channels * 2;
                fmt->blockAlign    = (short)(lwav.Channels * 2);
                fmt->bitsPerSample = 16;
                ptr += sizeof(fmt);

                *(int *)ptr = tag("data");
                ptr        += 4;
                *(int *)ptr = lwav.Samples.Length * 2;
                ptr        += 4;

                Marshal.Copy(lwav.Samples, 0, (IntPtr)ptr, lwav.Samples.Length);
                ptr += lwav.Samples.Length * 2;

                if (lwav.Looping)
                {
                    *(int *)ptr = tag("smpl");
                    ptr        += 4;
                    *(int *)ptr = sizeof(smpl) + sizeof(smpl_loop);
                    ptr        += 4;

                    smpl *smpl = (smpl *)ptr;
                    smpl->sampleLoopCount = 1;
                    ptr += sizeof(smpl);

                    smpl_loop *loop = (smpl_loop *)ptr;
                    loop->loopID    = 0;
                    loop->type      = 0;
                    loop->start     = lwav.LoopStart;
                    loop->end       = lwav.LoopEnd;
                    loop->fraction  = 0;
                    loop->playCount = 0;
                    ptr            += sizeof(smpl_loop);
                }
                return(data);
            }
        }
Exemple #24
0
 public void WriteFile(PCM16Audio lwav, string output_dir, string original_filename_no_ext)
 {
     sox.WriteFile(lwav, Path.Combine(output_dir, original_filename_no_ext + ".flac"));
 }