Domanda

Sto sviluppando un sistema come ausilio ai musicisti che eseguono la trascrizione.Lo scopo è quello di eseguire la trascrizione musicale automatica (non deve essere perfetta, poiché l'utente correggerà i difetti/errori in seguito) su una registrazione monofonica di un singolo strumento.Qualcuno qui ha esperienza nella trascrizione automatica della musica?O l'elaborazione del segnale digitale in generale?L'aiuto di chiunque è molto apprezzato, indipendentemente dal tuo background.

Finora ho studiato l'uso della trasformata veloce di Fourier per il rilevamento dell'altezza e una serie di test sia in MATLAB che nei miei programmi di test Java hanno dimostrato che è sufficientemente veloce e precisa per le mie esigenze.Un altro elemento del compito che dovrà essere affrontato è la visualizzazione dei dati MIDI prodotti sotto forma di spartito, ma di questo non mi occupo per ora.

In breve, quello che sto cercando è un buon metodo per il rilevamento dell'inizio delle note, ad es.la posizione nel segnale in cui inizia una nuova nota.Poiché gli esordi lenti possono essere piuttosto difficili da rilevare correttamente, inizialmente utilizzerò il sistema con registrazioni di pianoforte.Ciò è in parte dovuto anche al fatto che suono il pianoforte e dovrei essere in una posizione migliore per ottenere registrazioni adatte per i test.Come già detto, le prime versioni di questo sistema verranno utilizzate per semplici registrazioni monofoniche, per poi passare eventualmente a input più complessi a seconda dei progressi compiuti nelle prossime settimane.

È stato utile?

Soluzione

Ecco un grafico che illustra l'approccio della soglia per rilevare il rilevamento dell'insorgenza:

alt text

Questa immagine mostra un tipico file WAV con tre note discrete suonate in successione. La linea rossa rappresenta una soglia del segnale scelta e le linee blu rappresentano le posizioni di inizio della nota restituite da un semplice algoritmo che segna un inizio quando il livello del segnale supera la soglia.

Come mostra l'immagine, è difficile selezionare una soglia assoluta adeguata. In questo caso, la prima nota viene raccolta bene, la seconda nota viene persa completamente e la terza (a malapena) viene avviata molto tardi. In generale, una soglia bassa ti fa prendere le note fantasma, mentre alzarla ti fa perdere le note. Una soluzione a questo problema consiste nell'utilizzare una soglia relativa che innesca un avvio se il segnale aumenta di una determinata percentuale per un certo tempo, ma questo ha problemi propri.

Una soluzione più semplice consiste nell'utilizzare prima la compressione un po 'controintuitivamente denominata ( non la compressione MP3 - questo è qualcos'altro del tutto ) sul file wave. La compressione essenzialmente appiattisce i picchi nei dati audio e quindi amplifica tutto in modo che una parte maggiore dell'audio si avvicini ai valori massimi. L'effetto sul campione sopra sarebbe simile a questo (il che mostra perché il nome & Quot; compressione & Quot; sembra non avere senso - su apparecchiature audio di solito è etichettato & Quot; loudness & Quot; ):

alt text

Dopo la compressione, l'approccio della soglia assoluta funzionerà molto meglio (anche se è facile comprimere eccessivamente e iniziare a raccogliere gli avviamenti di note fittizie, lo stesso effetto della riduzione della soglia). Esistono molti editor di wave che fanno un buon lavoro di compressione, ed è meglio lasciarli gestire questo compito - probabilmente dovrai fare una buona quantità di lavoro & Quot; ripulire & Quot ; i tuoi file wave prima di rilevare comunque le note in essi.

In termini di codifica, un file WAV caricato in memoria è essenzialmente solo un array di numeri interi a due byte, dove 0 rappresenta nessun segnale e 32.767 e -32.768 rappresentano i picchi. Nella sua forma più semplice, un algoritmo di rilevamento della soglia si avviava dal primo campione e leggeva l'array fino a quando non trova un valore maggiore della soglia.

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

In pratica funziona in modo orribile, poiché l'audio normale ha tutti i tipi di picchi transitori al di sopra di una determinata soglia. Una soluzione consiste nell'utilizzare una potenza del segnale media corrente (ovvero non segnare un inizio fino a quando la media degli ultimi n campioni è sopra la soglia).

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);
    }
}

Tutto ciò richiede molte modifiche e giochiamo con le impostazioni per trovare le posizioni iniziali di un file WAV in modo accurato, e di solito ciò che funziona per un file non funzionerà molto bene su un altro. Questo è un dominio problematico molto difficile e non perfettamente risolto che hai scelto, ma penso sia bello che tu lo stia affrontando.

Aggiornamento: questo grafico mostra un dettaglio del rilevamento delle note che ho lasciato fuori, vale a dire quando termina la nota:

alt text

La linea gialla rappresenta la soglia off. Una volta che l'algoritmo ha rilevato l'inizio della nota, presuppone che la nota continui fino a quando l'intensità del segnale della media corrente scende al di sotto di questo valore (mostrato qui dalle linee viola). Questa è, ovviamente, un'altra fonte di difficoltà, come nel caso in cui due o più note si sovrappongono (polifonia).

Dopo aver rilevato i punti di inizio e di fine di ciascuna nota, è ora possibile analizzare ogni porzione di dati del file WAV per determinare le altezze.

Aggiornamento 2: ho appena letto la tua domanda aggiornata. Il rilevamento del tono tramite l'auto-correlazione è molto più semplice da implementare rispetto a FFT se si sta scrivendo da zero, ma se si è già estratto e si è utilizzata una libreria FFT pre-costruita,è meglio usarlo di sicuro. Dopo aver identificato le posizioni di inizio e di fine di ciascuna nota (e incluso un po 'di riempimento all'inizio e alla fine per l'attacco mancato e le porzioni di rilascio), ora puoi estrarre ogni porzione di dati audio e passarla a una funzione FFT per determina il tono.

Un punto importante qui non è usare una porzione di dati audio compressi, ma piuttosto usare una fetta di dati originali, non modificati. Il processo di compressione distorce l'audio e può produrre una lettura del pitch imprecisa.

Un ultimo punto sui tempi di attacco delle note è che potrebbe essere meno un problema di quanto pensi. Spesso nella musica uno strumento con un attacco lento (come un sintetizzatore soft) inizierà una nota prima di uno strumento di attacco acuto (come un piano) ed entrambe le note suoneranno come se iniziassero contemporaneamente. Se suoni strumenti in questo modo, l'algoritmo acquisisce la stessa ora di inizio per entrambi i tipi di strumenti, il che è positivo dal punto di vista WAV-MIDI.

Ultimo aggiornamento (spero): dimentica quello che ho detto sull'inclusione di alcuni campioni di padding dalla parte dell'attacco precoce di ogni nota - ho dimenticato che in realtà è una cattiva idea per il rilevamento del pitch. Le parti di attacco di molti strumenti (in particolare il piano e altri strumenti a percussione) contengono transitori che non sono multipli del tono fondamentale e tenderanno a rovinare il rilevamento del tono. Per questo motivo, vuoi iniziare ogni fetta un po 'dopo l'attacco.

Oh, e tipo di importante: il termine " compressione " qui non fa riferimento alla compressione in stile MP3 .

Aggiorna di nuovo: ecco una semplice funzione che esegue la compressione non dinamica:

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;
    }
}

Se param = 1.0, questa funzione non avrà alcun effetto sull'audio. Valori param più grandi (2.0 è buono, che quadrerà la differenza normalizzata tra ciascun campione e il valore di picco massimo) produrrà una maggiore compressione e un suono complessivo più forte (ma scadente). I valori inferiori a 1.0 produrranno un effetto di espansione.

Un altro punto probabilmente ovvio: dovresti registrare la musica in una piccola stanza non ecologica poiché gli echi sono spesso raccolti da questo algoritmo come note fantasma.

Aggiornamento: ecco una versione di StaticCompress che verrà compilata in C # ed esplicitamente lancerà tutto. Questo restituisce il risultato atteso:

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
}

Mi dispiace, il mio punteggio di conoscenza su Matlab è 0. Se hai pubblicato un'altra domanda sul perché la tua funzione Matlab non funziona come previsto, riceverà una risposta (ma non da me).

Altri suggerimenti

Ciò che vuoi fare viene spesso chiamato WAV in MIDI (google "wav-to-midi").Ci sono stati molti tentativi in ​​questo senso, con risultati variabili (l'inizio delle note è una delle difficoltà;la polifonia è molto più difficile da gestire).Consiglierei di iniziare con una ricerca approfondita delle soluzioni standard e di iniziare a lavorare da solo solo se non c'è nulla di accettabile là fuori.

L'altra parte del processo di cui avresti bisogno è qualcosa per rendere l'output MIDI come una partitura musicale tradizionale, ma ci sono innumerevoli miliardi di prodotti che lo fanno.

Un'altra risposta è:sì, ho eseguito molta elaborazione del segnale digitale (vedi il software sul mio sito Web: è un sintetizzatore software a voce infinita scritto in VB e C) e sono interessato ad aiutarti con questo problema.La parte WAV-to-MIDI non è poi così difficile concettualmente, è solo difficile farlo funzionare in modo affidabile nella pratica.L'inizio della nota è semplicemente l'impostazione di una soglia: gli errori possono essere facilmente regolati in avanti o all'indietro nel tempo per compensare le differenze di attacco delle note.Il rilevamento dell'intonazione è molto più semplice da eseguire su una registrazione che in tempo reale e richiede semplicemente l'implementazione di una routine di autocorrelazione.

Dovresti guardare MIRToolbox - è scritto per Matlab e ha un rilevatore di insorgenza incorporato - funziona abbastanza bene. Il codice sorgente è GPL, quindi puoi implementare l'algoritmo in qualunque linguaggio funzioni per te. Quale lingua utilizzerà il tuo codice di produzione?

questa libreria è incentrata sull'etichettatura audio:

aubio

  

aubio è una libreria per l'etichettatura audio. Le sue caratteristiche includono la segmentazione di un file audio prima di ogni suo attacco, l'esecuzione del rilevamento dell'intonazione, il battito del ritmo e la produzione di flussi midi dall'audio dal vivo. Il nome aubio deriva da "audio" con un refuso: è probabile che si verifichino anche diversi errori di trascrizione nei risultati.

e ho avuto fortuna con esso per il rilevamento dell'esordio e il rilevamento del tono. È in c, ma ci sono wrapper swig / python.

inoltre, l'autore della biblioteca ha un pdf della sua tesi sulla pagina, che contiene grandi informazioni e informazioni sull'etichettatura.

Gli insiemi duri vengono facilmente rilevati nel dominio del tempo utilizzando una misurazione media dell'energia.

SOMMA da 0 a N (X ^ 2)

Fallo con pezzi dell'intero segnale. Dovresti vedere dei picchi quando si verificano insorgenze (la dimensione della finestra dipende da te, il mio suggerimento è di 50ms o più).

Documenti completi sul rilevamento dell'insorgenza:

Per gli ingegneri hardcore:

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

Più facile da capire per la persona media:

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

Potresti provare a trasformare il segnale wav in un grafico di ampiezza rispetto al tempo. Quindi un modo per determinare un inizio coerente è calcolare l'intersezione di una tangente nel punto di flesso del fianco ascendente di un segnale con l'asse x.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top