Python 2.7 492 Bytes (nur beats.mp3)
Diese Antwort kann die Beats in identifizieren beats.mp3
, identifiziert jedoch nicht alle Noten auf beats2.mp3
oder noisy-beats.mp3
. Nach der Beschreibung meines Codes werde ich näher darauf eingehen, warum.
Dies verwendet PyDub ( https://github.com/jiaaro/pydub ), um die MP3 einzulesen. Alle anderen Verarbeitungen sind NumPy.
Golf Code
Nimmt ein einzelnes Befehlszeilenargument mit dem Dateinamen an. Es gibt jeden Schlag in ms in einer separaten Zeile aus.
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
Ungolfed Code
# 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
Warum ich Notizen zu den anderen Dateien vermisse (und warum sie unglaublich herausfordernd sind)
Mein Code untersucht Änderungen in der Signalstärke, um die Noten zu finden. Denn beats.mp3
das funktioniert wirklich gut. Dieses Spektrogramm zeigt, wie sich die Leistung über die Zeit (x-Achse) und die Frequenz (y-Achse) verteilt. Mein Code reduziert die y-Achse im Grunde genommen auf eine einzelne Zeile.
Visuell ist es sehr einfach zu erkennen, wo die Beats sind. Es gibt eine gelbe Linie, die sich immer wieder verjüngt. Ich ermutige Sie sehr, zuzuhörenbeats.mp3
während Sie dem Spektrogramm folgen, um zu sehen, wie es funktioniert.
Als nächstes gehe ich zu noisy-beats.mp3
(weil das eigentlich einfacher ist als ...) beats2.mp3
.
Noch einmal, sehen Sie, ob Sie die Aufnahme mitverfolgen können. Die meisten Zeilen sind schwächer, aber immer noch vorhanden Die leisen Noten fangen an, was es besonders schwierig macht, sie zu finden.
beats2.mp3
ist unglaublich herausfordernd. Hier ist das Spektrogramm.
Im ersten Bit gibt es einige Linien, aber einige Noten bluten wirklich über die Linien. Um Noten zuverlässig zu identifizieren, müssen Sie zunächst die Tonhöhe der Noten (Grund- und Obertöne) nachverfolgen und feststellen, wo sich diese ändern. Sobald das erste Bit funktioniert, ist das zweite Bit doppelt so hart wie das doppelte Tempo!
Grundsätzlich, um all dies zuverlässig zu identifizieren, ist meiner Meinung nach ein ausgefallener Notenerkennungscode erforderlich. Scheint, als wäre dies ein gutes Abschlussprojekt für jemanden in einer DSP-Klasse.