如何计算C#中波形信号的混响时间

时间:2012-12-23 22:50:40

标签: c# .net audio signal-processing

我正在尝试在C#中开发一个控制台应用程序,它使用WAV文件进行输入。应用程序应该按顺序完成一些事情,如下所示。首先,完整的代码:

class Program
{
static List<double> points = new List<double>();
static double maxValue = 0;
static double minValue = 1;
static int num = 0;
static int num2 = 0;
static List<double> values = new List<double>();
private static object akima;
static void Main(string[] args)
{
    string[] fileLines = File.ReadAllLines(args[0]);
    int count = 0;
    foreach (string fileLine in fileLines)
    {
        if (!fileLine.Contains(";"))
        {
            string processLine = fileLine.Trim();
            processLine = Regex.Replace(processLine, @"\s+", " ");
            if (Environment.OSVersion.Platform == PlatformID.Win32NT)
            {
                processLine = processLine.Replace(".", ",");
            }
            string[] dataParts = processLine.Split(Char.Parse(" "));
            points.Add(double.Parse(dataParts[0]));
            double value = Math.Pow(double.Parse(dataParts[1]), 2);
            if (value > maxValue)
            {
                maxValue = value;
                num = count;
            }
            values.Add(value);
        }
        count++;
    }
    for (int i = num; i < values.Count; i++)
    {
        if (values[i] < minValue)
        {
            minValue = values[i];
            num2 = i;
        }
    }
    Console.WriteLine(num + " " + num2);
    int between = num2 - num;
    points = points.GetRange(num, between);
    values = values.GetRange(num, between);
    List<double> defVal = new List<double>();
    List<double> defValPoints = new List<double>();
    alglib.spline1dinterpolant c;
    alglib.spline1dbuildakima(points.ToArray(), values.ToArray(), out c);
    double baseInt = alglib.spline1dintegrate(c, points[points.Count - 1]);
    List<double> defETC = new List<double>();
    for (int i = 0; i < points.Count; i += 10)
    {
        double toVal = points[i];
        defETC.Add(10 * Math.Log10(values[i]));
        defVal.Add(10 * Math.Log10((baseInt - alglib.spline1dintegrate(c, toVal)) / baseInt));
        defValPoints.Add(points[i]);
    }
    WriteDoubleArrayToFile(defValPoints.ToArray(), defVal.ToArray(), "test.dat");
    WriteDoubleArrayToFile(defValPoints.ToArray(), defETC.ToArray(), "etc.dat");
    int end = 0;
    for (int i = 0; i < points.Count; i++)
    {
        if (defVal[i] < -10)
        {
            end = i;
            break;
        }
    }
    //Console.WriteLine(num + " " + end);
    int beginEDT = num;
    int endEDT = num + end;
    double timeBetween = (defValPoints[endEDT] - defValPoints[beginEDT]) * 6;
    Console.WriteLine(timeBetween);
    for (int i = 0; i < points.Count; i++)
    {

    }
    Console.ReadLine();
}
static void WriteDoubleArrayToFile(double[] points, double[] values, string filename)
    {
        string[] defStr = new string[values.Length];
        for (int i = 0; i < values.Length; i++)
        {
        defStr[i] = String.Format("{0,10}{1,25}", points[i], values[i]);
        }
        File.WriteAllLines(filename, defStr);
    }
}
  1. 从WAV文件中提取decimal / float / double值
  2. 从提取的数据创建数组
  3. 创建一个能量时间曲线,以分贝的方式显示噪音/声音的衰减
  4. 从步骤3中创建的ETC创建衰减曲线
  5. 根据此衰减曲线计算早衰时间(EDT),T15 / T20和RT60。
  6. 在stdout中显示这些混响时间。
  7. 目前我有点像整个过程的一半。我会解释一下我做了什么:

    1. 我使用Sox将音频文件转换为带数字的.dat文件
    2. 我使用C#创建一个数组,只需将上面文件中的每一行拆分,然后将时间放在TimesArray中,将值放在ValuesArray中的那些点上。
    3. 我通过GNUPlot显示图表,使用此函数处理的数据:10 * Math.Log10(values [i]); (其中i是for循环中的迭代整数,迭代ValuesArray中的所有项目)
    4. 这是我开始陷入困境的地方。我的意思是,在这一步中,我使用Alglib的Akima Spline函数来集成一条线。我通过这个数学计算用Schroeder积分(反向)来做到这一点:10 * Math.Log10((baseInt-alglib.spline1dintegrate(c,toVal))/ baseInt); (其中baseInt是计算为完整曲线的基本积分的值,因此我有一个计算的反向Schroeder积分的底部部分.c是使用函数alglib.spline1dbuildakima时可用的spline1dinterpolant,它将timeArray作为x value,valueArray作为y值,c作为向外spline1dinterpolant.toval是点数组的x值。使用for循环选择特定值。)从这些新保存的值我想创建插值行并从该行计算RT60,但我不知道该怎么做。
    5. 试过,没有真正解决。
    6. 同上,我没有真正的值显示。
    7. 我现在很困惑,因为我不确定这是否是正确的方法。如果有人能告诉我如何在C#中以快速响应的方式计算混响时间,我会很高兴听到。这样做的方式可能与我现在的方式完全不同,没关系,请告诉我!

1 个答案:

答案 0 :(得分:1)

也许你需要以不同的方式解决这个问题:

  1. 从基础数学开始。找出这些函数的数学公式。
  2. 使用简单的数学函数并手动计算(在excel或matlab中)应该是什么值(所有这些东西ETC,DC,EDC,T15,T20,RT60) (正如您所需要的最小点数的正弦波函数)
  3. 然后编写一个单独的程序来评估C#中的每一个,并验证您的结果与excel / matlab的一致性。
  4. 在C#中,

    可能会将您的数据存储在一个类中,该类会传递给每个计算方法。

    你的主要功能应该是这样的:

    main(){
    
    data = new Data();
    
    //1, 2: 
    extract_data(data, filename);
    
    //3: 
    energy_time_curve(data)
    
    //...4, 5
    
    //6: 
    display_results(data);
    
    
    }