Как обнаружить тишину и вырезать mp3-файл без повторного кодирования с помощью NAudio and.NET

Я искал ответ везде, и я смог найти только некоторые кусочки. То, что я хочу сделать, это загрузить несколько mp3-файлов (временно объединить их), а затем разрезать их на куски, используя обнаружение тишины.

Я понимаю, что я могу использовать Mp3FileReader для этого, но вопросы: 1. Как прочитать, скажем, 20 секунд аудио из файла mp3? Нужно ли читать 20 раз reader.WaveFormat.AverageBytesPerSecond? Или, может быть, продолжайте читать кадры до суммы Mp3Frame.SampleCount / Mp3Frame.Пробоотборник превышает 20 секунд? 2. Как я на самом деле чувствую тишину? Я бы посмотрел на соответствующее количество последовательных образцов, чтобы проверить, все ли они ниже некоторого порога. Но как получить доступ к образцам независимо от того, 8 или 16bit, моно или стерео и т. д.? Могу ли я напрямую декодировать MP3-кадр? 3. После того, как я обнаружил тишину в say sample 10465, как мне сопоставить его с индексом кадра mp3 для выполнения резки без перекодировка?

3 ответов


ПЕРЕД ЧТЕНИЕМ НИЖЕ: ответ Марка намного проще реализовать, и вы почти наверняка будете довольны результатами. Этот ответ предназначен для тех, кто готов потратить на него чрезмерное количество времени.

таким образом, с учетом сказанного, вырезание MP3-файла на основе тишины без перекодирования или полного декодирования на самом деле возможно... В принципе, вы можете посмотреть на боковую информацию каждого кадра и данные gain & huffman каждой гранулы, чтобы "оценить" тишина.

  • найти тишину
  • скопируйте все кадры из до тишины в новый файл

теперь это становится сложным...

  • потяните аудиоданные из кадров после тишины, отслеживая, какой заголовок кадра идет с какими аудиоданными.
  • начните писать второй новый файл, но по мере записи кадров обновите поле main_data_begin, чтобы битовый резервуар синхронизировался с тем, где звуковые данные действительно быть.

вот подход, который я бы рекомендовал (который включает в себя повторное кодирование)

  1. использовать AudioFileReader чтобы получить MP3 в качестве образцов с плавающей запятой непосредственно в методе чтения
  2. найдите алгоритм шумовых ворот с открытым исходным кодом, перенесите его на C# и используйте его для обнаружения тишины (т. е. когда шумовые ворота закрыты, у вас есть тишина. Вы захотите настроить порог и время атаки / выпуска)
  3. создать производный ISampleProvider который использует шумовые ворота, и в его Read метод, не не возвращайте образцы, которые находятся в тишине
  4. либо: передайте вывод в WaveFileWriter для создания WAV-файла и кодирования wav-файла в MP3 Или: используйте NAudio.Хромой для кодирования непосредственно без шага WAV. Вероятно, вам нужно будет сначала перейти от SampleProvider к 16-битному WAV-провайдеру

MP3-это сжатый формат аудио. Вы не можете просто вырезать биты и ожидать, что оставшаяся часть по-прежнему будет действительным MP3-файлом. Фактически, поскольку это преобразование на основе DCT, биты находятся в частотной области вместо временной области. Для образца 10465 просто нет битов. Есть фрейм, который содержит образец 10465, и есть набор битов, описывающих все частоты в этом кадре.

простая резка звука на образце 10465 и продолжение с некоторым случайным другим образцом вероятно, вызывает разрыв, что означает количество частот, присутствующих в результирующем кадре. Так что это определенно означает полную перекодировку. Лучший способ плавного перехода, но это не тривиальная операция. И результат, конечно, немного отличается от входного, поэтому он по-прежнему означает перекодирование.

  1. Я не понимаю, почему вы все равно хотите прочитать 20 секунд аудио. Откуда этот номер? Вы обычно хотите читать всё.

  2. звук-это волна; вполне ожидаемо, что она пересекает ноль. Так что близость к нулю не является чем-то особенным. Для волны 20 Гц (порог слуха) нулевые пересечения происходят 40 раз в секунду, но каждый раз у вас будет несколько образцов около нуля. Таким образом, вам в основном нужно несколько образцов, которые близки к нулю, но с обеих сторон. 5 6 7 не так много для 16-битных звуков, но это вполне может быть частью волны, которая будет иметь максимум на 10000. Ты правда ... следует проверить не менее 0,05 секунды, чтобы поймать эти звуки 20 Гц.

  3. Так как вы обнаружили тишину в интервале 50 миллисекунд, у вас есть "положение", которое составляет примерно несколько сотен образцов в ширину. Если повезет, там есть граница кадра. Режь здесь. В противном случае пришло время для повторного кодирования.