/// <summary> /// Открывает файл с помощью диалога открытия файла /// </summary> /// <returns>Путь к преобразуемому файлу</returns> public static string OpenFileWithDialog() { try { OpenFileDialog openFile = new OpenFileDialog(); // Создаём диалог открытия файла openFile.Filter = "WAV|*.wav"; // Устанавливаем фильтр - только WAVE аудиофайлы openFile.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop); // Начальная директория поиска - рабочий стол openFile.Title = "Выберите преобразуемый аудиофайл"; // Указываем заголовок диалогового окна DialogResult openFileResult = openFile.ShowDialog(); // Вызываем диалог if (openFileResult == DialogResult.OK) // И обрабатываем его { return(openFile.FileName); } else { throw new Exception("Что-то пошло не так, либо операция открытия была прервана пользователем"); } } catch (Exception e) { ErrorShow.Print(e.Message, e.StackTrace, e.Source); return(null); } }
/// <summary> /// Метод, запрашивающий у пользователя путь для сохранения результата преобразования /// </summary> /// <returns>Путь для сохранения выходного файла</returns> public static string SaveFileWithDialog() { try { SaveFileDialog saveFile = new SaveFileDialog(); // Создаём диалог сохранения файла saveFile.Filter = "WAV|*.wav"; saveFile.InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop); // Начальная директория поиска - рабочий стол saveFile.Title = "Сохранение результата преобразования"; // Указываем заголовок диалогового окна DialogResult saveFileResult = saveFile.ShowDialog(); // Вызываем диалог if (saveFileResult == DialogResult.OK || saveFileResult == DialogResult.Yes) // И обрабатываем { return(saveFile.FileName); } else { throw new Exception("Что-то пошло не так или операция сохранения была прервана пользователем"); } } catch (Exception e) { ErrorShow.Print(e.Message, e.StackTrace, e.Source); return(null); } }
/// <summary> /// Преобразует 24-битные сэмплы в байты и записывает в новый файл со старым заголовком /// </summary> /// <param name="path">Путь к создаваемому файлу</param> /// <param name="sampleArray">Массив сэмплов</param> public unsafe void Write24BitSamples(string path, double[] sampleArray) { List <byte> all_new_audiofile = new List <byte>(); for (int i = 0; i < 44; i++) { all_new_audiofile.Add(Chunk.binary_data[i]); } for (int i = 0; i < sampleArray.Length; i++) { all_new_audiofile.Add(BitConverter.GetBytes(sampleArray[i])[0]); all_new_audiofile.Add(BitConverter.GetBytes(sampleArray[i])[1]); all_new_audiofile.Add(BitConverter.GetBytes(sampleArray[i])[2]); } using (FileStream fileStream = File.Create(path)) { fileStream.Write(all_new_audiofile.ToArray(), 0, all_new_audiofile.Count); } if (File.Exists(path)) { Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine("\nФайл успешно преобразован!\n"); Console.ForegroundColor = ConsoleColor.Gray; } else { ErrorShow.Print("Что-то пошло не так: файл не был создан по непонятной причине"); } }
/// <summary> /// Загружает в память указанный файл /// </summary> public void LoadFile() { try { using (FileStream file = File.OpenRead(Filename)) { if (file.CanRead) { int file_len = Convert.ToInt32(file.Length); byte[] tmpAudioBinBuffer = new byte[file_len]; file.Read(tmpAudioBinBuffer, 0, file_len); AudiofileBinData = tmpAudioBinBuffer; } else { throw new Exception("Невозможно открыть аудиофайл"); } } } catch (Exception e) { ErrorShow.Print(e.Message, e.StackTrace, e.Source); return; } }
/// <summary> /// Метод класса, отвечающий за извлечение сэмплов из аудиофайла с глубиной кодирования 16 бит /// </summary> /// <returns>Массив сэмплов</returns> public Int16[] Get16bitSamplesFromFile() { try { List <Int16> tmpSample = new List <Int16>(); for (int i = 0; i < AudioBinDataWithoutChunk.Length; i += 2) { byte[] tmp = new byte[2] { AudioBinDataWithoutChunk[i], AudioBinDataWithoutChunk[i + 1] }; ReadOnlySpan <byte> Span = new ReadOnlySpan <byte>(tmp); tmpSample.Add(BitConverter.ToInt16(Span)); } Samples_16_bit = tmpSample.ToArray(); } catch (Exception e) { ErrorShow.Print(e.Message, e.StackTrace, e.Source); return(null); } return(Samples_16_bit); }
/// <summary> /// Метод класса, непосредственно запрашивающий у пользователя команды /// </summary> private static void AskCommand() { int command_number = 0; Console.WriteLine("\nПрограмма готова к работе.\nДоступные действия:\n[1] Преобразовать файл, открытие через диалоговое окно\n[2] Преобразовать файл, путь к которому указывается вручную\n[3] Выход\n"); Console.Write("Выберите действие: "); try { try { command_number = Convert.ToInt32(Console.ReadLine()); // Считываем команду, приводим к целому числу } catch (Exception e) { ErrorShow.Print(e.Message, e.StackTrace, e.Source); } switch (command_number) // Обрабатываем введённый номер команды { case 0: break; case 1: Handle.ConvertFileWithDialog(); // Открытие и сохранение файла через диалоговое окно break; case 2: Handle.ConvertFileWithPath(); // Для любителей хардкора) Здесь пути прописываем вручную break; case 3: Handle.NormalExit(); // Выход break; default: throw new Exception("Вы ввели некорректный номер команды. Введённое значение: " + command_number); } } catch (Exception e) { ErrorShow.Print(e.Message, e.StackTrace, e.Source); } }
/// <summary> /// Получает заголовок из двоичных данных /// </summary> private unsafe void GetChunk() { try { for (int i = 0; i < 44; i++) { Chunk.binary_data[i] = AudiofileBinData[i]; } } catch (Exception e) { ErrorShow.Print(e.Message, e.StackTrace, e.Source); return; } }
/// <summary> /// Метод, который отвечает за преобразование файла. /// При этом файл открывается через диалоговое окно. /// </summary> public static void ConvertFileWithDialog() { try { string filePath = UI.OpenFileWithDialog(); // Открываем файл, записываем путь SampleParser sampleParser = new SampleParser(filePath); // Создаём экземпляр парсера сэмплов, в конструктор передаём путь // Обрабатываем открытый файл sampleParser.LoadFile(); sampleParser.ProcessingChunk(); Masking masking = null; // Создаём экземпляр класса для преобразования сэмплов // Смотрим, сколько каналов. Программа работает только со стерео. switch (sampleParser.Chunk.numOfChannels) { case 1: break; case 2: throw new Exception("Недопустимое число каналов. Стерео файлы не поддерживаются, только моно."); } // Проверяем глубину кодирования. Пока работаем только с PCM 16 бит switch (sampleParser.Chunk.pcm) { case 16: masking = new Masking(sampleParser.Get16bitSamplesFromFile()); // Создаём экземпляр, конструктору передаём сэмплы, которые мы вытащили из файла masking.BlockTransform(16); // Выполняем поблочное преобразование sampleParser.Write16BitSamples(UI.SaveFileWithDialog(), masking.FinalSampleArray16); // Записываем результат в новый файл, результат достаём из публичного метода класса Masking break; default: throw new Exception("Неподдерживаемая глубина кодирования: " + sampleParser.Chunk.pcm + " бит"); } } catch (Exception e) { ErrorShow.Print(e.Message, e.StackTrace, e.Source); } }
/// <summary> /// Читает полученный заголовок и получает данные о файле /// </summary> private unsafe void AnalyseChunk() { try { // Получаем количество каналов в аудиофайле byte[] tmpNoCarray = new byte[2] { Chunk.binary_data[22], Chunk.binary_data[23] }; ReadOnlySpan <byte> numOfChannelsSpan = new ReadOnlySpan <byte>(tmpNoCarray); Chunk.numOfChannels = BitConverter.ToInt16(numOfChannelsSpan); // Получаем частоту дискретизации byte[] tmpSRarray = new byte[4] { Chunk.binary_data[24], Chunk.binary_data[25], Chunk.binary_data[26], Chunk.binary_data[27] }; ReadOnlySpan <byte> sampleRateSpan = new ReadOnlySpan <byte>(tmpSRarray); Chunk.sampleRate = BitConverter.ToUInt16(sampleRateSpan); // Получаем глубину кодирования byte[] tmpPCMarray = new byte[2] { Chunk.binary_data[34], Chunk.binary_data[35] }; ReadOnlySpan <byte> pcmSpan = new ReadOnlySpan <byte>(tmpPCMarray); Chunk.pcm = BitConverter.ToInt16(pcmSpan); } catch (Exception e) { ErrorShow.Print(e.Message, e.StackTrace, e.Source); return; } }
/// <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> /// Записывает область данных, отсекая заголовок /// </summary> private void GetData() { try { byte[] tmpBinData = new byte[AudiofileBinData.Length - 44]; for (int i = 44; i < AudiofileBinData.Length; i++) { tmpBinData[i - 44] = AudiofileBinData[i]; } AudioBinDataWithoutChunk = tmpBinData; } catch (Exception e) { ErrorShow.Print(e.Message, e.StackTrace, e.Source); return; } }
/// <summary> /// Метод, который также отвечает за преобразование файла. /// При этом путь к файлу указывается вручную. /// </summary> public static void ConvertFileWithPath() { try { string filePath = UI.OpenFileAtPath(); SampleParser sampleParser = new SampleParser(filePath); sampleParser.LoadFile(); sampleParser.ProcessingChunk(); Masking masking = null; switch (sampleParser.Chunk.numOfChannels) { case 1: break; case 2: throw new Exception("Недопустимое число каналов. Стерео файлы не поддерживаются, только моно."); } switch (sampleParser.Chunk.pcm) { case 16: masking = new Masking(sampleParser.Get16bitSamplesFromFile()); masking.BlockTransform(16); sampleParser.Write16BitSamples(UI.SaveFileAtPath(), masking.FinalSampleArray16); break; default: throw new Exception("Неподдерживаемая глубина кодирования: " + sampleParser.Chunk.pcm + " бит"); } } catch (Exception e) { ErrorShow.Print(e.Message, e.StackTrace, e.Source); } }