Pergunta

Tenho a tarefa de criar um aplicativo cliente .NET para detectar silêncio em arquivos WAV.

Isso é possível com as APIs integradas do Windows?Ou, alternativamente, alguma boa biblioteca disponível para ajudar com isso?

Foi útil?

Solução

A análise de áudio é algo difícil que requer muita matemática complexa (pense nas Transformadas de Fourier).A pergunta que você deve fazer é “o que é o silêncio”.Se o áudio que você está tentando editar for capturado de uma fonte analógica, é provável que não haja silêncio...serão apenas áreas de ruído suave (zumbido de linha, ruído de fundo ambiente, etc.).

Dito isso, um algoritmo que deveria funcionar seria determinar um limite mínimo de volume (amplitude) e duração (digamos, <10dbA por mais de 2 segundos) e então simplesmente fazer uma análise de volume da forma de onda procurando por áreas que atendam a esse critério (talvez com alguns filtros para picos de milissegundos).Eu nunca escrevi isso em C#, mas isso Artigo do CodeProject parece interessante;descreve o código C# para desenhar uma forma de onda ...esse é o mesmo tipo de código que poderia ser usado para fazer outras análises de amplitude.

Outras dicas

http://www.codeproject.com/Articles/19590/WAVE-File-Processor-in-C

Ele contém todo o código necessário para eliminar o silêncio e misturar arquivos wave.

Aproveitar.

Se você deseja calcular com eficiência a potência média em uma janela deslizante:eleve ao quadrado cada amostra e, em seguida, adicione-a a um total acumulado.Subtraia o valor ao quadrado das N amostras anteriores.Em seguida, passe para a próxima etapa.Esta é a forma mais simples de um CIC Filtro. Teorema de Parseval nos diz que este cálculo de potência é aplicável aos domínios do tempo e da frequência.

Além disso, você pode querer adicionar Histerese ao sistema para evitar ligar e desligar rapidamente quando o nível de potência estiver oscilando em torno do nível limite.

estou a usar NAudio, e eu queria detectar o silêncio em arquivos de áudio para poder reportar ou truncar.

Depois de muita pesquisa, cheguei a esta implementação básica.Então, escrevi um método de extensão para o AudioFileReader classe que retorna a duração do silêncio no início/fim do arquivo, ou a partir de uma posição específica.

Aqui:

static class AudioFileReaderExt
{
    public enum SilenceLocation { Start, End }

    private static bool IsSilence(float amplitude, sbyte threshold)
    {
        double dB = 20 * Math.Log10(Math.Abs(amplitude));
        return dB < threshold;
    }
    public static TimeSpan GetSilenceDuration(this AudioFileReader reader,
                                              SilenceLocation location,
                                              sbyte silenceThreshold = -40)
    {
        int counter = 0;
        bool volumeFound = false;
        bool eof = false;
        long oldPosition = reader.Position;

        var buffer = new float[reader.WaveFormat.SampleRate * 4];
        while (!volumeFound && !eof)
        {
            int samplesRead = reader.Read(buffer, 0, buffer.Length);
            if (samplesRead == 0)
                eof = true;

            for (int n = 0; n < samplesRead; n++)
            {
                if (IsSilence(buffer[n], silenceThreshold))
                {
                    counter++;
                }
                else
                {
                    if (location == SilenceLocation.Start)
                    {
                        volumeFound = true;
                        break;
                    }
                    else if (location == SilenceLocation.End)
                    {
                        counter = 0;
                    }
                }
            }
        }

        // reset position
        reader.Position = oldPosition;

        double silenceSamples = (double)counter / reader.WaveFormat.Channels;
        double silenceDuration = (silenceSamples / reader.WaveFormat.SampleRate) * 1000;
        return TimeSpan.FromMilliseconds(silenceDuration);
    }
}

Isto aceitará quase qualquer formato de arquivo de áudio não apenas WAV.

Uso:

using (AudioFileReader reader = new AudioFileReader(filePath))
{
    TimeSpan duration = reader.GetSilenceDuration(AudioFileReaderExt.SilenceLocation.Start);
    Console.WriteLine(duration.TotalMilliseconds);
}

Referências:

Não acho que você encontrará APIs integradas para detecção de silêncio.Mas você sempre pode usar o bom e velho processamento de sinal matemático/discreto para descobrir o volume.Aqui está um pequeno exemplo: http://msdn.microsoft.com/en-us/magazine/cc163341.aspx

Usar Sox.Ele pode remover silêncios iniciais e finais, mas você terá que chamá-lo como um exe do seu aplicativo.

Veja o código abaixo de Detectando silêncio de áudio em arquivos WAV usando C#

private static void SkipSilent(string fileName, short silentLevel)
{
    WaveReader wr = new WaveReader(File.OpenRead(fileName));
    IntPtr format = wr.ReadFormat();
    WaveWriter ww = new WaveWriter(File.Create(fileName + ".wav"), 
        AudioCompressionManager.FormatBytes(format));
    int i = 0;
    while (true)
    {
        byte[] data = wr.ReadData(i, 1);
        if (data.Length == 0)
        {
            break;
        }
        if (!AudioCompressionManager.CheckSilent(format, data, silentLevel))
        {
            ww.WriteData(data);
        }
    }
    ww.Close();
    wr.Close();
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top