Tìm nhịp đập trong tệp MP3


27

Trong thử thách này, nhiệm vụ của bạn là thực hiện một bản ghi đơn giản ở định dạng mp3 và tìm thời gian bù cho nhịp đập trong tệp. Hai bản ghi ví dụ ở đây:

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

Đây là bản ghi thứ ba có nhiều tiếng ồn hơn hai bản trước:

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

Ví dụ, bản ghi đầu tiên dài 65 giây và chứa chính xác (trừ khi tôi nghe nhầm!) 76 nhịp. Công việc của bạn là tạo ra một chương trình lấy một tệp mp3 như là đầu vào và xuất ra một chuỗi thời gian bù trừ tính bằng mili giây của nhịp đập trong tệp. Một nhịp được xác định là xảy ra, tất nhiên, khi người chơi ghi-ta chơi một hoặc nhiều dây.

Giải pháp của bạn phải:

  • Làm việc trên bất kỳ tệp mp3 có "độ phức tạp" tương tự. Nó có thể thất bại với các bản thu âm ồn ào hoặc các giai điệu được phát nhanh - tôi không quan tâm.
  • Hãy khá chính xác. Dung sai là +/- 50 ms. Vì vậy, nếu nhịp xảy ra ở 1500 ms và giải pháp của bạn báo cáo 1400, thì điều đó là không thể chấp nhận được.
  • Chỉ sử dụng phần mềm miễn phí. Gọi ffmpeg được cho phép như đang sử dụng bất kỳ phần mềm bên thứ ba có sẵn miễn phí nào cho ngôn ngữ bạn chọn.

Tiêu chí chiến thắng là khả năng phát hiện thành công nhịp đập mặc dù có nhiễu trong các tệp được cung cấp. Trong trường hợp hòa, giải pháp ngắn nhất sẽ thắng (độ dài của mã bên thứ 3 không được thêm vào số đếm).


1
Mặc dù điều này có vẻ thú vị, nhưng đây là một cuộc thi, bạn nên xác định tiêu chí chiến thắng chính xác hơn là "Chính xác".
Fabinout

ok tốt hơn bây giờ ??
Bjorn Lindqvist

18
Một cuộc thi tốt cô lập phần quan tâm. Ở đây bạn có vẻ quan tâm đến nhận dạng nhịp, đó chắc chắn là một vấn đề DSP thú vị. Vậy tại sao làm cho các chương trình xử lý (hoặc thuê ngoài) sự phức tạp của định dạng tệp MP3? Câu hỏi sẽ được cải thiện bằng cách lấy RAW (với các giả định được phép về tốc độ mẫu, độ sâu bit và độ bền) hoặc WAV (tương tự).
Peter Taylor

3
Quan điểm của cuộc thi là xử lý tất cả những phần đó. Có lẽ điều đó làm cho nó khó giải quyết nó trong bản golf nếu nó gặp khó khăn khi giao tiếp với mp3. Không bao giờ ít hơn, thách thức được chỉ định rõ và (afaict) hoàn toàn về chủ đề nên sự tiêu cực là rất mất tinh thần.
Bjorn Lindqvist

8
@ BjornLindqvist Bạn không nên đưa ra gợi ý để cải thiện trái tim. Trừ khi một số bình luận trước đó đã bị xóa, tôi không thấy bất kỳ bình luận tiêu cực nào ở đây, chỉ là những gợi ý để cải thiện.
Gareth

Câu trả lời:


6

Python 2.7 492 byte (chỉ beats.mp3)

Câu trả lời này có thể xác định các nhịp trong beats.mp3, nhưng sẽ không xác định tất cả các ghi chú trên beats2.mp3hoặc noisy-beats.mp3. Sau phần mô tả mã của tôi, tôi sẽ đi vào chi tiết tại sao.

Điều này sử dụng PyDub ( https://github.com/jiaaro/pydub ) để đọc trong MP3. Tất cả các xử lý khác là NumPy.

Mã đánh gôn

Đưa ra một đối số dòng lệnh với tên tệp. Nó sẽ xuất ra từng nhịp trong ms trên một dòng riêng biệt.

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

Mã bị đánh cắp

# 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

Tại sao tôi bỏ lỡ ghi chú trên các tệp khác (và tại sao chúng rất khó khăn)

Mã của tôi xem xét các thay đổi về công suất tín hiệu để tìm ghi chú. Đối với beats.mp3, điều này hoạt động thực sự tốt. Biểu đồ phổ này cho thấy công suất được phân phối theo thời gian (trục x) và tần số (trục y). Mã của tôi về cơ bản thu gọn trục y xuống một dòng. beats.jpeg Trực quan, thật dễ dàng để xem nhịp đập ở đâu. Có một đường màu vàng lặp đi lặp lại. Tôi rất khuyến khích bạn lắng nghe beats.mp3trong khi bạn theo dõi trên phổ để xem nó hoạt động như thế nào.

Tiếp theo tôi sẽ đi đến noisy-beats.mp3(vì điều đó thực sự dễ dàng hơn beats2.mp3. ồn ào-beats.pngMột lần nữa, hãy xem liệu bạn có thể làm theo cùng với ghi âm hay không. Hầu hết các dòng đều mờ hơn, nhưng vẫn ở đó. Tuy nhiên, ở một số điểm, chuỗi phía dưới vẫn đổ chuông khi các ghi chú yên tĩnh bắt đầu. Điều đó làm cho việc tìm kiếm chúng đặc biệt khó khăn, bởi vì bây giờ, bạn phải tìm thấy chúng bằng cách thay đổi tần số (trục y) thay vì chỉ biên độ.

beats2.mp3là một thách thức vô cùng. Đây là quang phổ beats2.jpeg Trong bit đầu tiên, có một số dòng, nhưng một số ghi chú thực sự chảy qua các dòng. Để xác định một cách đáng tin cậy các ghi chú, bạn phải bắt đầu theo dõi cao độ của các ghi chú (cơ bản và hài hòa) và xem những thay đổi đó. Khi bit thứ nhất hoạt động, bit thứ hai cứng gấp đôi nhịp độ gấp đôi!

Về cơ bản, để xác định một cách đáng tin cậy tất cả những điều này, tôi nghĩ rằng nó cần một số mã phát hiện ghi chú ưa thích. Có vẻ như đây sẽ là một dự án tốt cuối cùng cho một người trong lớp DSP.


Tôi nghĩ rằng điều này là không được phép, bởi vì nó không đáp ứng tất cả các yêu cầu. Câu trả lời tốt, nhưng nó cần một số công việc.
Rɪᴋᴇʀ

Vâng, tôi hơi thất vọng phương pháp này đã không thành công như tôi hy vọng. Tôi nghĩ rằng điều này có thể giúp đỡ người khác muốn đâm vào nó. Nếu tôi có chút thời gian rảnh trong tuần này, tôi hy vọng sẽ thử một cách tiếp cận dựa trên FFT mới sẽ cho kết quả tốt hơn.
Đaminh A.

Được, tuyệt đấy. Công việc tốt mặc dù.
Rɪᴋᴇʀ
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.