MP3 dosyasındaki vuruşları bulma


27

Bu zorlu görevde, göreviniz mp3 formatında basit bir kayıt yapmak ve dosyadaki atımların zaman aralıklarını bulmak. İki örnek kayıt burada:

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

İşte iki öncekinden çok daha fazla gürültüye sahip üçüncü kayıt:

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

Örneğin, ilk kayıt 65 saniye uzunluğunda ve tam olarak (yanlış saymadığım sürece!) 76 vuruş içeriyor. İşiniz, giriş gibi bir mp3 dosyasını alan ve zaman atımlarının bir dizisini dosyadaki atımların milisaniye cinsinden çıkaran bir program tasarlamaktır. Elbette, gitaristin çaldığı bir veya daha fazla teli topladığı zaman, bir ritimin oluşması tanımlanır.

Çözümünüz:

  • Benzer "karmaşıklık" herhangi bir mp3 dosyası üzerinde çalışın. Gürültülü kayıtlarda veya hızlıca çalınan melodilerde başarısız olabilir - umrumda değil.
  • Oldukça kesin olun. Tolerans +/- 50 ms'dir. Öyleyse vuruş 1500 msnde meydana gelirse ve çözümünüz 1400 bildirirse, bu kabul edilemez.
  • Sadece ücretsiz yazılımı kullanın. Ffmpeg'i çağırmak, kendi diliniz için özgürce temin edilebilecek herhangi bir üçüncü taraf yazılımını kullanmak gibi.

Kazanan kriterler, verilen dosyalardaki gürültüye rağmen atımları başarılı bir şekilde tespit edebilme yeteneğidir. Beraberlik durumunda, en kısa çözüm kazanır (3. taraf kodunun uzunluğu hesaba eklenmez).


1
Bu ilginç görünse de, bu bir yarışmadır, kazanan kriterleri "Doğruluk" dan daha kesin olarak tanımlamanız gerekir.
Fabinout

tamam şimdi daha iyi?
Björn Lindqvist

18
İyi bir yarışma ilgi alanını izole eder. Burada kesinlikle ilginç bir DSP problemi olan ritmi tanımlama ile ilgileniyor gibisiniz. Öyleyse neden programlar MP3 dosya formatının karmaşıklığını ele alıyor (ya da dış kaynak kullanıyor)? Soru, RAW (örnekleme hızı, bit derinliği ve endianness hakkında izin verilen varsayımlarla) veya WAV (benzer şekilde) alarak geliştirilecektir.
Peter Taylor,

3
Yarışmanın amacı bu parçaları ele almak. Belki de mp3'lerle etkileşime geçmekte zorlanıyorsa, golf senaryosunda çözmeyi zorlaştırır. Asla az değil, zorluk tam olarak belirlenmiş ve (olumsuz) tamamen olumsuz bir konu olduğu için olumsuzluk çok dehşet verici.
Björn Lindqvist

8
@ BjörnLindqvist Kalbe iyileştirme önerileri almamalısınız. Önceki bir yorum silinmediyse, burada hiçbir olumsuz yorum görmüyorum, yalnızca iyileştirmeler için önerilerde bulunuyorum.
Gareth

Yanıtlar:


6

Python 2.7 492 bayt (yalnızca beats.mp3)

Bu cevap, içindeki atımları tanımlayabilir beats.mp3, ancak beats2.mp3veya üzerindeki tüm notları tanımlamayacaktır noisy-beats.mp3. Kodumun açıklamasından sonra, neden olarak ayrıntıya gireceğim.

Bu, MP3'te okumak için PyDub ( https://github.com/jiaaro/pydub ) kullanır . Diğer tüm işlemler NumPy'dir.

Golf Kodu

Dosya adı ile tek bir komut satırı argümanı alır. Her atımı ms cinsinden ayrı bir satıra gönderir.

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 Kodu

# 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

Neden diğer dosyalardaki notları özlüyorum (ve neden inanılmaz zorlu)

Kodum, notları bulmak için sinyal gücündeki değişikliklere bakar. Çünkü beats.mp3bu gerçekten iyi çalışıyor. Bu spektrogram gücün zaman (x ekseni) ve frekans (y ekseni) boyunca nasıl dağıldığını gösterir. Kodum temel olarak y eksenini tek bir satıra indirdi. beats.jpeg Görsel olarak, vuruşların nerede olduğunu görmek gerçekten kolay. Tekrar tekrar süzülen sarı bir çizgi var. beats.mp3Nasıl çalıştığını görmek için spektrogramı takip ederken dinlemenizi şiddetle tavsiye ediyorum .

Sonraki Ben gidersiniz noisy-beats.mp3daha doğrusu kolay olduğu için ( beats2.mp3. Gürültülü-beats.pngHala orada hatlarının çoğu daha sönük. Eğer kayıt ile birlikte takip edebilir, bakalım kez daha. Ama. Ancak bazı noktalarda alt dize hala zaman çalıyor sessiz notlar başlıyor, bu onları bulmayı özellikle zorlaştırıyor, çünkü şimdi onları sadece genlikten ziyade frekanstaki (y ekseni) değişikliklerle bulmanız gerekiyor.

beats2.mp3inanılmaz derecede zorlu. İşte spektrogram İşte beats2.jpeg ilk bitinde bazı çizgiler var, ancak bazı notlar çizgiler üzerinde gerçekten kanıyor. Notları güvenilir bir şekilde tanımlamak için notların perdesini izlemeye başlamanız (temel ve harmonikler) ve bunların nerede değiştiğini görmeniz gerekir. İlk bit çalıştığında, ikinci bit tempo'nun iki katına katlanır!

Temel olarak, bunların tümünü güvenilir bir şekilde tanımlamak için, bir miktar fantezi not algılama kodu aldığını düşünüyorum. Görünüşe göre bu DSP sınıfındaki biri için iyi bir son proje olacak.


Buna izin verilmediğini düşünüyorum, çünkü tüm talepleri yerine getirmiyor. İyi cevap, ama biraz çalışmaya ihtiyacı var.
Rɪᴋᴇʀ

Evet, bu yöntemin umduğum gibi işe yaramadığını biraz hayal kırıklığına uğrattım. Bunun bıçaklamak isteyen birine yardımcı olabileceğini düşünüyorum. Bu hafta biraz boş zaman alırsam, daha iyi sonuçlar vermesi gereken yeni bir FFT tabanlı yaklaşım denemeyi umuyorum.
Dominic A.

Peki tamam. Yine de iyi iş.
Rɪᴋᴇʀ
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.