Python 2.7 492 ไบต์ (beats.mp3 เท่านั้น)
คำตอบนี้สามารถระบุเต้นในbeats.mp3
แต่จะไม่ระบุบันทึกทั้งหมดบนหรือbeats2.mp3
noisy-beats.mp3
หลังจากคำอธิบายรหัสของฉันฉันจะเข้าไปดูรายละเอียดว่าทำไม
สิ่งนี้ใช้ PyDub ( https://github.com/jiaaro/pydub ) เพื่ออ่านใน MP3 การประมวลผลอื่น ๆ ทั้งหมดคือ NumPy
รหัส Golfed
รับอาร์กิวเมนต์บรรทัดคำสั่งเดียวพร้อมชื่อไฟล์ มันจะออกแต่ละจังหวะเป็น ms ในแต่ละบรรทัด
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
รหัสที่ไม่ดี
# 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
ทำไมฉันถึงคิดถึงโน้ตของไฟล์อื่น ๆ (และทำไมมันถึงท้าทายอย่างเหลือเชื่อ)
รหัสของฉันดูที่การเปลี่ยนแปลงกำลังงานของสัญญาณเพื่อค้นหาบันทึกย่อ สำหรับbeats.mp3
วิธีนี้ใช้งานได้ดีจริงๆ สเปกโตรแกรมนี้แสดงให้เห็นว่ากำลังกระจายอย่างไรเมื่อเวลาผ่านไป (แกน x) และความถี่ (แกน y) โดยทั่วไปโค้ดของฉันจะยุบแกน y ลงไปเป็นบรรทัดเดียว
มันง่ายมากที่จะดูว่ามันอยู่ที่ไหน มีเส้นสีเหลืองที่ลดลงอีกครั้งและอีกครั้ง ฉันขอแนะนำให้คุณฟังbeats.mp3
ในขณะที่คุณติดตามบน spectrogram เพื่อดูว่ามันทำงานอย่างไร
ต่อไปฉันจะไปที่noisy-beats.mp3
(เพราะมันง่ายกว่าจริงbeats2.mp3
ๆ
อีกครั้งดูว่าคุณสามารถติดตามพร้อมกับการบันทึกได้หรือไม่ส่วนใหญ่ของบรรทัดนั้นซีดกว่า แต่ยังอยู่ที่นั่นอย่างไรก็ตามในบางจุดสตริงด้านล่างยังคงดังขึ้นเมื่อ โน้ตเงียบเริ่มต้นที่ทำให้การค้นหายากเป็นพิเศษเพราะตอนนี้คุณต้องค้นหาโดยการเปลี่ยนแปลงความถี่ (แกน y) แทนที่จะเป็นแอมพลิจูด
beats2.mp3
ท้าทายอย่างไม่น่าเชื่อ นี่คือสเปกโทรแกรม
ในบิตแรกมีบางบรรทัด แต่บางบันทึกย่อมีเลือดออกเหนือเส้น ในการระบุโน้ตได้อย่างน่าเชื่อถือคุณจะต้องเริ่มการติดตามระดับเสียงของโน้ต (พื้นฐานและเสียงประสาน) และดูว่าการเปลี่ยนแปลงเหล่านั้นอยู่ที่ไหน เมื่อบิตแรกทำงานบิตที่สองนั้นหนักหน่วงกว่าสองเท่าของจังหวะ!
โดยทั่วไปเพื่อระบุสิ่งเหล่านี้ได้อย่างน่าเชื่อถือฉันคิดว่ามันต้องใช้รหัสตรวจจับบันทึกย่อแฟนซี ดูเหมือนว่านี่จะเป็นโครงการสุดท้ายที่ดีสำหรับใครบางคนในคลาส DSP