Domanda

Con risorse limitate come CPU più lente, dimensioni del codice e RAM, qual è il modo migliore per rilevare l'altezza di una nota musicale, in modo simile a ciò che farebbe un accordatore elettronico o software?

Dovrei usare:

  • Bacia FFT
  • FFTW
  • Trasformata wavelet discreta
  • autocorrelazione
  • analisi del passaggio per lo zero
  • filtri spaziati in ottave

altro?

In poche parole, quello che sto cercando di fare è riconoscere una singola nota musicale, due ottave sotto il Do centrale e due ottave sopra, suonata su qualsiasi strumento (ragionevole).Vorrei essere entro il 20% del semitono: in altre parole, se l'utente suona in modo troppo bemolle o troppo diesis, devo distinguerlo.Tuttavia, non avrò bisogno della precisione richiesta per l'accordatura.

È stato utile?

Soluzione

Se non hai bisogno di tanta precisione, una FFT potrebbe essere sufficiente. Finestra prima il pezzo di audio in modo da ottenere picchi ben definiti, quindi trovare il primo picco significativo.

Larghezza contenitore = frequenza di campionamento/dimensione FFT:

Fondamenti gamma da Da 20 Hz a 7 kHz, quindi una frequenza di campionamento di 14 kHz sarebbe sufficiente.La successiva frequenza di campionamento "standard" è 22050 Hz.

La dimensione FFT viene quindi determinata dalla precisione desiderata.L'uscita FFT è lineare in frequenza, mentre i toni musicali sono logaritmici in frequenza, quindi la precisione nel caso peggiore sarà alle basse frequenze.Per il 20% di un semitono a 20 Hz è necessaria una larghezza di 1,2 Hz, il che significa una lunghezza FFT di 18545.La successiva potenza di due è 215 = 32768.Si tratta di 1,5 secondi di dati e il calcolo richiede al processore del mio laptop 3 ms.

Questo non funzionerà con i segnali che hanno un "fondamentale mancante", e trovare il "primo picco significativo" è alquanto difficile (poiché le armoniche sono spesso più alte della fondamentale), ma puoi trovare un modo adatto alla tua situazione.

Autocorrelazione e spettro prodotto armonico sono più bravi a trovare la vera fondamentale di un'onda invece che una delle armoniche, ma non penso che si occupino altrettanto bene inarmonicità, e la maggior parte degli strumenti come il pianoforte o la chitarra sono inarmonici (gli armonici sono leggermente acute rispetto a come dovrebbero essere).Dipende davvero dalle circostanze, però.

Inoltre, puoi risparmiare ancora più cicli del processore eseguendo i calcoli solo all'interno di una specifica banda di frequenza di interesse, utilizzando il Trasformata Chirp-Z.

Ho scritto alcuni metodi diversi in Python a scopo di confronto.

Altri suggerimenti

Se vuoi eseguire il riconoscimento dell'altezza in tempo reale (e con precisione entro 1/100 di semitono), la tua unica vera speranza è l'approccio zero-crossing.Ed è una flebile speranza, mi dispiace dirlo.Il passaggio allo zero può stimare l'altezza solo da un paio di lunghezze d'onda dei dati e può essere eseguito con la potenza di elaborazione di uno smartphone, ma non è particolarmente accurato, poiché piccoli errori nella misurazione delle lunghezze d'onda provocano grandi errori nella frequenza stimata.Dispositivi come i sintetizzatori per chitarra (che deducono l'altezza da una corda di chitarra con solo un paio di lunghezze d'onda) funzionano quantizzando le misurazioni in note della scala.Questo potrebbe funzionare per i tuoi scopi, ma tieni presente che il passaggio allo zero funziona benissimo con forme d'onda semplici, ma tende a funzionare sempre meno bene con suoni di strumenti più complessi.

Nella mia applicazione (un sintetizzatore software che gira su smartphone) utilizzo le registrazioni di note di singoli strumenti come materia prima per la sintesi wavetable e, per produrre note con un'altezza particolare, ho bisogno di conoscere l'altezza fondamentale di una registrazione, un'accurata entro 1/1000 di semitono (in realtà ho solo bisogno di una precisione di 1/100, ma sono un disturbo ossessivo compulsivo a riguardo).L'approccio zero-crossing lo è tanto troppo impreciso per questo, e gli approcci basati su FFT sono troppo imprecisi o troppo lenti (o entrambi a volte).

L'approccio migliore che ho trovato in questo caso è utilizzare l'autocorrelazione.Con l'autocorrelazione sostanzialmente indovini l'altezza e quindi misuri l'autocorrelazione del tuo campione alla lunghezza d'onda corrispondente.Analizzando la gamma di altezze plausibili (ad esempio da LA = 55 Hz a LA = 880 Hz) per semitoni, individui l'altezza più correlata, quindi eseguo una scansione più dettagliata nelle vicinanze di quell'altezza per ottenere un risultato valore più accurato.

L'approccio migliore per te dipende interamente dallo scopo per cui stai cercando di utilizzarlo.

Non ho familiarità con tutti i metodi che menzioni, ma ciò che scegli dovrebbe dipendere principalmente dalla natura dei tuoi dati di input.Stai analizzando toni puri o la tua sorgente di input ha più note?Il parlato è una caratteristica del tuo input?Ci sono limitazioni sulla durata del tempo a disposizione per campionare l'input?Sei in grado di barattare una certa precisione con la velocità?

In una certa misura, ciò che scegli dipende anche dal fatto che desideri eseguire i calcoli tempo o dentro spazio delle frequenze.Conversione di a serie temporali per una rappresentazione in frequenza ci vuole tempo, ma nella mia esperienza tende a dare risultati migliori.

Autocorrelazione confronta due segnali nel dominio del tempo.Un'implementazione ingenua è semplice ma relativamente costosa da calcolare, poiché richiede una differenziazione a coppie tra tutti i punti nei segnali originali e spostati nel tempo, seguita dalla differenziazione per identificare i punti di svolta nella funzione di autocorrelazione e quindi dalla selezione del minimo corrispondente a la frequenza fondamentale.Esistono metodi alternativi.Per esempio, Differenza di grandezza media è una forma di autocorrelazione molto economica, ma la precisione ne risente.Tutte le tecniche di autocorrelazione corrono il rischio di errori di ottava, poiché nella funzione esistono picchi diversi da quello fondamentale.

Misurare punti di passaggio per lo zero è semplice e diretto, ma si verificheranno problemi se nel segnale sono presenti più forme d'onda.

Nello spazio delle frequenze, tecniche basate su FFT potrebbe essere abbastanza efficiente per i tuoi scopi.Un esempio è la tecnica dello spettro del prodotto armonico, che confronta lo spettro di potenza del segnale con le versioni sottocampionate per ciascuna armonica e identifica l'altezza moltiplicando insieme gli spettri per produrre un picco chiaro.

Come sempre, non esiste alcun sostituto per testare e profilare diverse tecniche, per determinare empiricamente cosa funzionerà meglio per il tuo problema e i tuoi vincoli.

Una risposta come questa non può che scalfire la superficie di questo argomento.Oltre ai collegamenti precedenti, ecco alcuni riferimenti rilevanti per ulteriori letture.

Nel mio progetto Danstuner, ho preso il codice da Audacia.In sostanza è stata necessaria una FFT, quindi è stata trovata la potenza di picco inserendo una curva cubica sulla FFT e trovando il picco di quella curva.Funziona abbastanza bene, anche se ho dovuto guardarmi dai salti di ottava.

Vedere Spettro.cpp.

Il passaggio per lo zero non funzionerà perché un suono tipico ha armoniche e passaggi per lo zero molto più della frequenza di base.

Qualcosa che ho sperimentato (come progetto lato casa) è stato questo:

  1. Campiona il suono con ADC alla frequenza di campionamento di cui hai bisogno.
  2. Rilevare i livelli dei picchi positivi e negativi a breve termine della forma d'onda (finestra scorrevole o simile).Cioè.un rilevatore di buste.
  3. Crea un'onda quadra che diventa alta quando la forma d'onda rientra nel 90% (o giù di lì) dell'inviluppo positivo e diminuisce quando la forma d'onda rientra nel 90% dell'inviluppo negativo.Cioè.un'onda quadra con isteresi.
  4. Misura la frequenza di quell'onda quadra con calcoli semplici di conteggio/tempo, utilizzando tutti i campioni necessari per ottenere la precisione richiesta.

Tuttavia ho scoperto che con gli input della mia tastiera elettronica, per alcuni suoni strumentali è riuscita a captare 2 volte la frequenza di base (ottava successiva).Questo era un progetto parallelo e non sono mai riuscito a implementare una soluzione prima di passare ad altre cose.Ma pensavo che promettesse di comportare un carico della CPU molto inferiore rispetto a FFT.

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