Pergunta

Estou desenvolvendo um sistema como uma ajuda para músicos executam a transcrição. O objetivo é realizar a transcrição automática de música (ele não tem que ser perfeito, como o usuário irá corrigir glitches / erros posteriores) sobre uma gravação monofônica único instrumento. Alguém aqui tem experiência na transcrição automática de música? Ou sinal digital de processamento em geral? Ajuda de ninguém é muito apreciado, não importa o que seu fundo.

Até agora, tenho investigado o uso da Transformada Rápida de Fourier para detecção de tom, e uma série de testes em ambos os meus próprios programas de teste Java MATLAB e mostraram-no para ser o suficiente rápido e preciso para minhas necessidades. Outro elemento da tarefa que terá de ser abordado é a exibição dos dados MIDI produzidos em forma de folha de música, mas isso é algo que eu não estou preocupado com o agora.

Em resumo, o que eu estou procurando é um bom método para a detecção de início de nota, ou seja, a posição no sinal em que uma nova nota começa. Como inícios lentos pode ser bastante difícil de detectar corretamente, eu será inicialmente usando o sistema com gravações de piano. Este também é parcialmente devido ao fato de eu tocar piano e deve estar em uma posição melhor para obter gravações adequado para testes. Como dito acima, as primeiras versões deste sistema será usado para gravações monofônicos simples, possivelmente progredindo depois para a entrada mais complexa dependendo do progresso feito nas próximas semanas.

Foi útil?

Solução

Aqui está um gráfico que ilustra a abordagem limiar notar detecção de início:

text alt

Esta imagem mostra um arquivo WAV típico com três notas discretas jogado em sucessão. A linha vermelha representa um limiar de sinal escolhido, e as linhas azuis representam posições de início de notas retornados por um algoritmo simples que as marcas de um começo, quando o nível do sinal cruza o limiar.

Como a imagem mostra, selecionando um limiar absoluto adequada é difícil. Neste caso, a primeira nota é captado bem, a segunda nota é completamente perdido, e a terceira nota (mal) é iniciado muito tarde. Em geral, um limiar baixo faz com que você pegar notas fantasmas, enquanto a elevar faz com que você notas perder. Uma solução para este problema é a utilização de um limite relativo que desencadeia um começo, se os aumentos de sinal de uma determinada percentagem ao longo de um determinado período de tempo, mas isso tem seus próprios problemas.

A solução mais simples é usar a compressão um pouco-contraintuitivamente chamado ( não compressão de MP3 - que é algo completamente diferente ) em seu arquivo de onda em primeiro lugar. Compressão essencialmente achata os picos em seus dados de áudio e amplifica tudo para que mais do áudio está perto dos valores máximos. O efeito sobre o exemplo acima ficaria assim (que mostra por que o nome "compressão" parece não fazer sentido - em equipamentos de áudio normalmente é rotulado de "loudness"):

text alt

Após a compressão, a abordagem limiar absoluto funcionará muito melhor (embora seja fácil para o excesso de compressa e começar a pegar começa notas fictícias, o mesmo efeito como a redução do limiar). Há um monte de editores de onda lá fora, que fazem um bom trabalho de compressão, e é melhor deixá-los lidar com essa tarefa - você provavelmente vai precisar fazer uma quantidade razoável de trabalho "limpar" seus arquivos de onda antes de detectar notas em -los de qualquer maneira.

Em termos de codificação, um ficheiro WAV carregado para a memória é essencialmente apenas uma matriz de números inteiros de dois bytes, em que 0 representa ausência de sinal e 32.767 e 32.768 representam os picos. Na sua forma mais simples, um algoritmo de detecção de limiar só iria começar na primeira amostra e ler através da matriz até encontrar um valor maior do que o limiar.

short threshold = 10000;
for (int i = 0; i < samples.Length; i++)
{
    if ((short)Math.Abs(samples[i]) > threshold) 
    {
        // here is one note onset point
    }
}

Na prática, isso funciona horrivelmente, desde áudio normal tem todos os tipos de picos transitórios acima de um dado limiar. Uma solução é a utilização de uma intensidade de sinal média de execução (isto é, não marcar um início até a média dos últimos amostras n for superior ao limiar).

short threshold = 10000;
int window_length = 100;
int running_total = 0;
// tally up the first window_length samples
for (int i = 0; i < window_length; i++)
{
    running_total += samples[i];
}
// calculate moving average
for (int i = window_length; i < samples.Length; i++)
{
    // remove oldest sample and add current
    running_total -= samples[i - window_length];
    running_total += samples[i];
    short moving_average = running_total / window_length;
    if (moving_average > threshold)
    {
        // here is one note onset point 
        int onset_point = i - (window_length / 2);
    }
}

Tudo isso requer muito ajustes e brincar com as configurações para obtê-lo a encontrar as posições de início de um arquivo WAV com precisão, e geralmente o que funciona para um arquivo não vai funcionar muito bem em outro. Este é um domínio problema muito difícil e não-perfeitamente-resolvido que você escolheu, mas eu acho que é legal que você está enfrentá-lo.

Update: este gráfico mostra um detalhe de detecção de nota eu deixei de fora, ou seja, detectar quando as extremidades Nota:

text alt

A linha amarela representa a off-limite. Uma vez que o algoritmo detectou uma nota início, ele assume a nota continua até que a intensidade do sinal de média móvel cai abaixo deste valor (mostrado pelas linhas de roxo). Este é, naturalmente, uma outra fonte de dificuldades, como é o caso em que duas ou mais notas sobrepõem (polifonia).

Uma vez que você detectou os pontos de início e de parada de cada nota, agora você pode analisar cada fatia de dados de arquivos WAV para determinar os arremessos.

Update 2: Acabei de ler sua pergunta atualizado. Pitch-detecção através de auto-correlação é muito mais fácil de implementar do que FFT se você estiver escrevendo o seu próprio a partir do zero, mas se você já check-out e usado uma biblioteca FFT pré-construído, você é melhor off usá-lo com certeza. Depois de identificar as posições de início e de parada de cada nota (e incluído algum estofamento no início e fim para o ataque falhou e porções de libertação), agora você pode retirar cada fatia de dados de áudio e passá-lo para uma função FFT para determinar a altura.

Um ponto importante aqui é não usar uma fatia dos dados de áudio comprimido, mas sim para usar uma fatia do original, os dados não modificados. Os distorce processo de compressão do áudio e pode produzir uma leitura campo impreciso.

Um último ponto sobre tempos de ataque nota é que ele pode ser um problema menor do que você pensa. Muitas vezes na música um instrumento com um ataque lento (como um soft synth) começará uma nota mais cedo do que um instrumento de ataque afiada (como um piano) e ambas as notas irá soar como se eles estão começando ao mesmo tempo. Se você está instrumentos jogar dessa maneira, o algoritmo com pegar a mesma hora de início para ambos os tipos de instrumentos, o que é bom do ponto de vista WAV-to-MIDI.

Última atualização (espero): Esqueça o que eu disse sobre a inclusão de algumas amostras preenchimentos da parte ataque no início de cada nota - Eu esqueci esta é realmente uma má idéia para detecção de campo. As porções de ataque de muitos instrumentos (especialmente piano e outros instrumentos do tipo de percussão) contêm transientes que não são múltiplos da altura fundamental, e tenderão a estragar detecção de arremesso. Você realmente quer começar cada fatia um pouco depois do ataque por este motivo.

Oh, e tipo de importante:. o termo "compactação" aqui não se refere a MP3-style compressão

Update novamente: aqui é uma função simples que faz a compressão não dinâmica:

public void StaticCompress(short[] samples, float param)
{
    for (int i = 0; i < samples.Length; i++)
    {
        int sign = (samples[i] < 0) ? -1 : 1;
        float norm = ABS(samples[i] / 32768); // NOT short.MaxValue
        norm = 1.0 - POW(1.0 - norm, param);
        samples[i] = 32768 * norm * sign;
    }
}

Quando param = 1.0, esta função não terá nenhum efeito sobre o áudio. Valores maiores param (2.0 é boa, o que será quadrado da diferença normalizada entre cada amostra e o valor de pico máximo) irá produzir mais de compressão e uma (mas de baixa qualidade) som mais alto global. Valores abaixo de 1,0 irá produzir um efeito de expansão.

Um outro ponto provavelmente óbvio:. Você deve gravar a música em um quarto pequeno, não-echoic desde ecos são muitas vezes apanhados por este algoritmo como notas fantasmas

Update: aqui é uma versão do StaticCompress que irá compilar em C # e moldes explicitamente tudo. Isso retorna o resultado esperado:

public void StaticCompress(short[] samples, double param)
{
    for (int i = 0; i < samples.Length; i++)
    {
        Compress(ref samples[i], param);
    }
}

public void Compress(ref short orig, double param)
{
    double sign = 1;
    if (orig < 0)
    {
        sign = -1;
    }
    // 32768 is max abs value of a short. best practice is to pre-
    // normalize data or use peak value in place of 32768
    double norm = Math.Abs((double)orig / 32768.0);
    norm = 1.0 - Math.Pow(1.0 - norm, param);
    orig = (short)(32768.0 * norm * sign); // should round before cast,
        // but won't affect note onset detection
}

Desculpe, minha pontuação conhecimento sobre Matlab é 0. Se você postou outra pergunta sobre o porquê de sua função Matlab não funciona como esperado seria obter resposta (não apenas por mim).

Outras dicas

O que você quer fazer é muitas vezes chamado WAV-to-MIDI (google "wav-to-midi"). Tem havido muitas tentativas de este processo, com resultados variados (nota início é uma das dificuldades; polifonia é muito mais difícil de lidar com). Eu recomendo começar com uma pesquisa aprofundada das soluções off-the-shelf, e só começar a trabalhar em seu próprio país, se não há nada fora aceitável lá.

A outra parte do processo que você precisa é algo para tornar a saída MIDI como uma partitura musical tradicional, mas há umpteen bilhões de produtos que fazem isso.

Outra resposta é: sim, eu fiz um monte de processamento de sinal digital (consulte o software no meu site - é um sintetizador de software infinito-voz escrito em VB e C), e estou interessado em ajudá-lo com este problema. A parte WAV-to-MIDI não é realmente tão difícil conceitualmente, é só fazê-lo funcionar de forma confiável na prática isso é difícil. Nota início é apenas a criação de um limite - erros podem ser facilmente ajustado para a frente ou para trás no tempo para compensar as diferenças nota de ataque. detecção de tom é muito mais fácil de fazer em uma gravação do que está a fazer em tempo real, e envolve apenas a implementação de uma rotina de auto-correlação.

Você deve olhar para MIRToolbox - está escrito em Matlab, e tem um detector início construída em - ele funciona muito bem. O código-fonte é GPL, para que possa implementar o algoritmo em qualquer língua funciona para você. Que língua é o seu código de produção vai usar?

esta biblioteca é centrado em torno rotulagem áudio:

aubio

aubio é uma biblioteca para rotulagem de áudio. Suas características incluem segmentar um arquivo de som antes de cada um dos seus ataques, realizando detecção de tom, batendo a batida e produzindo fluxos midi de áudio ao vivo. O nome aubio vem de 'audio' com um erro de digitação:. Vários erros de transcrição são susceptíveis de ser encontrado nos resultados demasiado

e eu tive sorte com ele para a detecção de início e de detecção de campo. É em c, mas não há gole / python wrappers.

Além disso, o autor da biblioteca tem um pdf de sua tese sobre a página, que tem grande informação e de fundo sobre rotulagem.

onsets rígidos são facilmente detectados no domínio do tempo usando uma medição de energia média.

somatório de 0 a N (X ^ 2)

Faça isso com pedaços de todo o sinal. Você deve ver os picos quando ocorrem latências (o tamanho da janela é com você, minha sugestão é 50ms ou mais).

Papers extensivas sobre a detecção Onset:

Para hardcore Engenheiros:

http://www.nyu.edu/classes/bello/MIR_files /2005_BelloEtAl_IEEE_TSALP.pdf

Mais fácil para a pessoa média de compreender:

http://bingweb.binghamton.edu/~ahess2/Onset_Detection_Nov302011.pdf

Você poderia tentar transformar o sinal wav em um gráfico de amplitude contra o tempo. Em seguida, uma maneira de determinar um início consistente é calcular a intersecção da tangente no ponto de inflexão do flanco subida de um sinal com o eixo x.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top