public static decimal GetLoudness(string fileName, Action <double, double> updateProgress = null) { if (Path.GetExtension(fileName) != ".wav") { return(defaultLoadness); } try { WavReader wavReader; using (FileStream fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read)) { wavReader = new WavReader(fileStream, Encoding.Default); } WavReader.FmtChunk fmt = (WavReader.FmtChunk)wavReader.Riff.Chunks["fmt "]; double[][] buffer = wavReader.GetSampleData(); R128LufsMeter r128LufsMeter = new R128LufsMeter(); r128LufsMeter.Prepare(fmt.SampleRate, buffer.Length); r128LufsMeter.StartIntegrated(); r128LufsMeter.ProcessBuffer(buffer, (double current, double total) => { updateProgress?.Invoke(current, total); }); r128LufsMeter.StopIntegrated(); // Report input loudness return(-16 - Convert.ToDecimal(r128LufsMeter.IntegratedLoudness)); } catch (Exception ex) { return(defaultLoadness); } }
private double Loudness(byte[] pcmData) { List <double> data = new List <double>(); for (int i = 0; i < pcmData.Length; i += 2) { data.Add((double)BitConverter.ToInt16(pcmData, i) / (short.MaxValue + 1)); } R128LufsMeter r128LufsMeter = new R128LufsMeter(); r128LufsMeter.Prepare(AudioSampleRate, 1); r128LufsMeter.StartIntegrated(); r128LufsMeter.ProcessBuffer(new double[][] { data.ToArray() }, null); r128LufsMeter.StopIntegrated(); double loudness = r128LufsMeter.IntegratedLoudness; if (double.IsNaN(loudness)) { return(0); } if (loudness <= -70.0) { return(0); } if (loudness >= 0.0) { return(100.0); } return((loudness + 70.0) * LUFSToPercent); }
/// <summary> /// Normalize a buffer /// </summary> /// <param name="buffer">The buffer need to be normalize</param> /// <param name="sampleRate">The sample rate of the sample data</param> /// <returns>Normalized buffer</returns> public static double[][] Normalize(double[][] buffer, double sampleRate) { // Calc input loudness R128LufsMeter r128LufsMeter = new R128LufsMeter(); r128LufsMeter.Prepare(sampleRate, buffer.Length); Console.Write("Calculating input loudness..."); r128LufsMeter.StartIntegrated(); r128LufsMeter.ProcessBuffer(buffer, (double current, double total) => { AppendConsoleProgressBar($"Calculating input loudness : {current:N0}/{total:N0}", (double)current / total); }); r128LufsMeter.StopIntegrated(); // Report input loudness double integratedLoudness = r128LufsMeter.IntegratedLoudness; ConsoleClearLine(); Console.WriteLine("Input integrated loudness : {0:N} LU", integratedLoudness); // Normalization to -23 LU double targetLoudness = TargetIntegratedLufs; double gain = targetLoudness - integratedLoudness; int count = 0; double[][] clone = null; while (Math.Abs(targetLoudness - integratedLoudness) > 0.5) { count++; // Clone buffer clone = new double[buffer.Length][]; for (int i = 0; i < buffer.Length; i++) { clone[i] = (double[])buffer[i].Clone(); } // Apply gain to normalize Console.Write("Applying gain..."); Gain.ApplyGain(clone, gain); ConsoleClearLine(); Console.WriteLine($"Gain applyed : {gain:N} dB"); // Limit the True Peak StreamWriter streamWriter = new StreamWriter("limiter.csv"); int c = 0; TruePeakLimiter.ProcessBuffer(clone, MaximumTruePeak, sampleRate, LimiterAttack, LimiterRelease, LimiterAttackCurve, LimiterReleaseCurve, (double current, double total) => { if (current % 10000 == 0) { AppendConsoleProgressBar($"Limiting : {current:N0}/{total:N0}", (double)current / total); } }); ConsoleClearLine(); Console.WriteLine("Limiting finished!"); streamWriter.Close(); // Calc output loudness Console.Write("Verifying output loudness..."); r128LufsMeter.StartIntegrated(); r128LufsMeter.ProcessBuffer(clone, (double current, double total) => { AppendConsoleProgressBar($"Verifying output loudness : {current:N0}/{total:N0}", (double)current / total); }); r128LufsMeter.StopIntegrated(); // Report output loudness integratedLoudness = r128LufsMeter.IntegratedLoudness; ConsoleClearLine(); Console.WriteLine("Output integrated loudness {0} : {1:N} LU", count, integratedLoudness); gain += targetLoudness - integratedLoudness; if (!LoopVerify) { break; } } if (clone != null) { return(clone); } return(buffer); }