Trova i battiti in un file MP3


27

In questa sfida, il tuo compito è quello di prendere una semplice registrazione in formato mp3 e trovare gli offset di tempo dei battiti nel file. Sono disponibili due registrazioni di esempio:

https://dl.dropboxusercontent.com/u/24197429/beats.mp3 https://dl.dropboxusercontent.com/u/24197429/beats2.mp3

Ecco la terza registrazione con molto più rumore rispetto alle due precedenti:

https://dl.dropboxusercontent.com/u/24197429/noisy-beats.mp3

Ad esempio, la prima registrazione dura 65 secondi e contiene esattamente (a meno che non abbia contato male!) 76 battiti. Il tuo compito è ideare un programma che accetta un file mp3 come input e genera una sequenza degli offset di tempo in millisecondi dei battiti nel file. Viene definito un ritmo, ovviamente, quando il chitarrista suona pizzica una o più corde.

La tua soluzione deve:

  • Lavora su qualsiasi file mp3 di simile "complessità". Può non riuscire a registrare rumorose o a suonare rapidamente melodie - non mi interessa.
  • Sii abbastanza preciso. La tolleranza è di +/- 50 ms. Quindi, se il ritmo si verifica a 1500 ms e la soluzione riporta 1400, questo è inaccettabile.
  • Utilizzare solo software gratuito. La chiamata a ffmpeg è consentita così come l'utilizzo di qualsiasi software di terze parti disponibile gratuitamente nella tua lingua preferita.

Il criterio vincente è la capacità di rilevare correttamente i battiti nonostante il rumore nei file forniti. In caso di pareggio, vince la soluzione più breve (la lunghezza del codice di terze parti non viene aggiunta al conteggio).


1
Anche se questo sembra interessante, questo è un concorso, è necessario definire i criteri di vincita più precisamente della "correttezza".
Fabinout,

ok meglio adesso ??
Björn Lindqvist,

18
Un buon concorso isola la parte di interesse. Qui sembra che tu sia interessato all'identificazione del battito, che è certamente un problema DSP interessante. Allora perché i programmi gestiscono (o esternalizzano) le complessità del formato di file MP3? La domanda sarebbe migliorata prendendo RAW (con ipotesi consentite su frequenza di campionamento, profondità di bit e endianness) o WAV (in modo simile).
Peter Taylor,

3
Il punto del concorso è gestire tutti quei pezzi. Forse questo rende difficile risolverlo in golfscript se ha difficoltà a interfacciarsi con gli mp3. Tuttavia, la sfida è ben specificata e (afaict) completamente in argomento, quindi la negatività è molto allarmante.
Björn Lindqvist,

8
@ BjörnLindqvist Non dovresti prendere suggerimenti per migliorare il cuore. A meno che alcuni commenti precedenti non siano stati eliminati, non vedo alcun commento negativo qui, solo suggerimenti per miglioramenti.
Gareth

Risposte:


6

Python 2.7 492 byte (solo beats.mp3)

Questa risposta può identificare i battiti in beats.mp3, ma non identificherà tutte le note su beats2.mp3o noisy-beats.mp3. Dopo la descrizione del mio codice, entrerò nei dettagli sul perché.

Questo utilizza PyDub ( https://github.com/jiaaro/pydub ) per leggere in MP3. Tutte le altre elaborazioni sono NumPy.

Codice Golfed

Accetta un singolo argomento della riga di comando con il nome del file. Emetterà ogni battito in ms su una riga separata.

import sys
from math import *
from numpy import *
from pydub import AudioSegment
p=square(AudioSegment.from_mp3(sys.argv[1]).set_channels(1).get_array_of_samples())
n=len(p)
t=arange(n)/44.1
h=array([.54-.46*cos(i/477) for i in range(3001)])
p=convolve(p,h, 'same')
d=[p[i]-p[max(0,i-500)] for i in xrange(n)]
e=sort(d)
e=d>e[int(.94*n)]
i=0
while i<n:
 if e[i]:
  u=o=0
  j=i
  while u<2e3:
   u=0 if e[j] else u+1
   #u=(0,u+1)[e[j]]
   o+=e[j]
   j+=1
  if o>500:
   print "%g"%t[argmax(d[i:j])+i]
  i=j
 i+=1

Codice Ungolfed

# Import stuff
import sys
from math import *
from numpy import *
from pydub import AudioSegment

# Read in the audio file, convert from stereo to mono
song = AudioSegment.from_mp3(sys.argv[1]).set_channels(1).get_array_of_samples()

# Convert to power by squaring it
signal = square(song)
numSamples = len(signal)

# Create an array with the times stored in ms, instead of samples
times = arange(numSamples)/44.1

# Create a Hamming Window and filter the data with it. This gets rid of a lot of
# high frequency stuff.
h = array([.54-.46*cos(i/477) for i in range(3001)])
signal = convolve(signal,h, 'same') #The same flag gets rid of the time shift from this

# Differentiate the filtered signal to find where the power jumps up.
# To reduce noise from the operation, instead of using the previous sample,
# use the sample 500 samples ago.
diff = [signal[i] - signal[max(0,i-500)] for i in xrange(numSamples)]

# Identify the top 6% of the derivative values as possible beats
ecdf = sort(diff)
exceedsThresh = diff > ecdf[int(.94*numSamples)]

# Actually identify possible peaks
i = 0
while i < numSamples:
 if exceedsThresh[i]:
  underThresh = overThresh = 0
  j=i
  # Keep saving values until 2000 consecutive ones are under the threshold (~50ms)
  while underThresh < 2000:
   underThresh =0 if exceedsThresh[j] else underThresh+1
   overThresh += exceedsThresh[j]
   j += 1
  # If at least 500 of those samples were over the threshold, take the maximum one
  # to be the beat definition
  if overThresh > 500:
   print "%g"%times[argmax(diff[i:j])+i]
  i=j
 i+=1

Perché mi mancano le note sugli altri file (e perché sono incredibilmente difficili)

Il mio codice esamina i cambiamenti nella potenza del segnale al fine di trovare le note. Per beats.mp3questo funziona davvero bene. Questo spettrogramma mostra come viene distribuita la potenza nel tempo (asse x) e frequenza (asse y). Il mio codice sostanzialmente comprime l'asse y su una sola riga. beats.jpeg Visivamente, è davvero facile vedere dove sono i battiti. C'è una linea gialla che si assottiglia ancora e ancora. Ti incoraggio vivamente ad ascoltare beats.mp3mentre segui lo spettrogramma per vedere come funziona.

Poi andrò a noisy-beats.mp3(perché in realtà è più facile di beats2.mp3... rumoroso-beats.pngAncora una volta, vedi se riesci a seguire insieme alla registrazione. La maggior parte delle linee sono più deboli, ma sono ancora lì. Tuttavia, in alcuni punti, la stringa inferiore continua a squillare quando iniziano le note tranquille, il che rende particolarmente difficile trovarle, perché ora le devi trovare in base ai cambiamenti di frequenza (l'asse y) piuttosto che all'ampiezza.

beats2.mp3è incredibilmente stimolante. Ecco lo spettrogramma beats2.jpeg Nel primo bit, ci sono alcune linee, ma alcune note sanguinano davvero sopra le linee. Per identificare le note in modo affidabile, dovresti iniziare a tracciare il tono delle note (fondamentali e armoniche) e vedere dove cambiano. Una volta che il primo bit funziona, il secondo bit è due volte più duro del doppio del tempo!

Fondamentalmente, per identificare tutti questi in modo affidabile, penso che ci voglia un po 'di codice di rilevamento delle note fantasiose. Sembra che questo sarebbe un buon progetto finale per qualcuno in una classe DSP.


Penso che questo non sia permesso, perché non soddisfa tutti i requisiti. Buona risposta, ma ha bisogno di un po 'di lavoro.
Rɪᴋᴇʀ

Sì, sono un po 'deluso che questo metodo non abbia funzionato come speravo. Immagino che questo potrebbe aiutare qualcun altro che vuole prenderlo a pugni. Se avrò del tempo libero questa settimana, spero di provare un nuovo approccio basato su FFT che dovrebbe dare risultati migliori.
Domenico A.

Va bene, d'accordo. Bel lavoro però.
R
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.