/// <summary> /// Метод класса, реализующий обратное дискретное преобразование Фурье /// На выходе получаем массив 16-битных сэмплов /// </summary> /// <param name="spectre">Спектр</param> /// <param name="N">Длина исходного массива сэмплов</param> /// <returns>Выходной массив сэмплов</returns> public unsafe static Int16[] ReverseFourierTransform16bit(Structures.Spectre spectre, int N) { Int16[] sampleArray = new Int16[N]; for (int i = 0; i < N; i++) { double ans = 0; for (int j = 0; j < (N / 2); j++) { ans += (spectre.a[j] * Math.Cos((2 * Math.PI * j * i) / (N))) + (spectre.b[j] * Math.Sin((2 * Math.PI * j * i) / (N))); } sampleArray[i] = (Int16)((double)((double)ans * (double)((double)2 / (double)N))); } return(sampleArray); }
/// <summary> /// Метод класса, выполняющий инверсию спектра /// </summary> /// <param name="spectre">Спектр в исходном порядке</param> /// <param name="lenght">Длина массивов в структуре</param> /// <returns>Спектр в обратном порядке</returns> private unsafe Structures.Spectre Inverse(Structures.Spectre spectre, int lenght) { Structures.Spectre ret_spectre; try { for (int i = 0; i < lenght; i++) { ret_spectre.a[i] = spectre.a[(lenght - 1) - i]; ret_spectre.b[i] = spectre.b[(lenght - 1) - i]; } } catch (Exception e) { ErrorShow.Print(e.Message, e.StackTrace, e.Source); } return(ret_spectre); }
/// <summary> /// Метод класса, производящий поблочное преобразование массива сэмплов /// Преобрахование включает в себя такие операции с каждым блоком: /// 1. Преобразование Фурье на участке в 128 сэмплов, который, собственно и является блоком; /// 2. Инверсия спектра; /// 3. Обратное дискретное преобразование Фурье; /// </summary> /// <param name="pcm">Глубина кодирования в битах</param> public void BlockTransform(int pcm) { switch (pcm) { case 16: { List <Int16> tmpFinal = new List <Int16>(); // Создаём временный список для работы for (int i = 0; i < InputSampleArray_16bit.Length; i += 128) // Цикл, обрабатывающий один блок из 128 сэмплов { Int16[] tmp = new Int16[128]; // Создаём массив для данного блока for (int j = 0; j < 128; j++) // И записываем в него сэмплы из общего массива { tmp[j] = InputSampleArray_16bit[i + j]; } Structures.Spectre spectre = DiscreteFourierTransformClass.DiscreteFourierTransform(tmp); // Создаём структуру, хранящую спектр данного блока Structures.Spectre tmpSpectre = Inverse(spectre, 64); // Делаем инверсию полученного спектра, результат храним во временной структуре spectre = tmpSpectre; tmp = DiscreteFourierTransformClass.ReverseFourierTransform16bit(spectre, 128); // Проводим обратное преобразование Фурье tmpFinal.AddRange(tmp); // Получившийся блок записываем во временный список if ((InputSampleArray_16bit.Length - (i + 128)) < 128) // Если размер файла не кратен 128, во избежание переполнения игнорируем последний неполный блок. Оставшиеся несколько сэмплов не будут иметь значения. { break; } } FinalSampleArray16 = tmpFinal.ToArray(); } break; } }