打印歌词“ Twinkle Twinkle Little Star”


24

您的目标是在演奏每个音符时将歌词打印到歌曲“ Twinkle Twinkle Little Star”上。

电脑的麦克风会听到音符。如果音符的音高(但不一定是音高)正确,请打印适当的音节。否则,什么都不做。每个音符将至少有半秒长,并且音符之间的间隔至少为四分之一秒。

使用此处提供的音符和以下歌词:(垂直线表示音节休止符。)

双| kle,双| kle,点燃的星星,

我怎么想你是什么。

在如此高的世界上

像天空中的钻石。

双| kle,双| kle,点燃的星星,

我怎么想你是什么。

音乐的录音可以在这里找到。

电脑听到中间的C并打印“ Twin”

它听到另一个中间C并打印“ kle”,

然后它听到另一个中间的C(错误的音符),并且什么也不做。

然后,它听到中间C上方的G并打印“双胞胎”,依此类推。

规则

  • 标点必须如图所示。
  • 间距必须如图所示(带有空格和换行符)。
  • 可以将空白与上一个或下一个音节一起打印。

2
有什么方法可以放松“必须在票据结束前打印?” 使用1/16秒的音符,即使您将3/4的时间用于采样,也只能使用约47ms的声音。这为中音提供了相当模糊的频率分辨率。
Geobits 2014年

@Geobits好点;我删除了该规则。
Ypnypn 2014年

1
这是我能找到的第一个使用音频输入的难题!恭喜!
不是查尔斯(Charles)

1
标题是否拼写错误以区分两个闪烁?
Rainbolt

1
我们可以链接到音频文件进行测试吗?
加尔文的爱好2014年

Answers:


7

蟒3 -部分溶液(760 742 734 710 705 657字符)

(最后编辑;我保证)

这似乎是一个非常,非常漂亮,非常困难的问题(特别是识别音符的开始或结束位置)。音乐的自动转录似乎是一个开放的研究课题(并不是我对此一无所知)。因此,这是一个不做任何音符分段的部分解决方案(例如,它在听到频率时立即一次打印“ Twinkle”),并且可能仅适用于该特定的ogg文件:

A=-52
F=44100
C=4096
import pyaudio as P
import array
import scipy.signal as G
import numpy as N
import math
L=math.log
i=0
j=[9,2,0,2,4,5,7,9]
k=[2,4,5,7]
n=j+k+k+j
w="Twinkle, |twinkle, |little |star,\n|How I |wonder |what you |are.\n|Up a|bove the |world so |high,\n|Like a |diamond |in the |sky.\n".split('|')
w+=w[:8]
e=P.PyAudio().open(F,1,8,1,0,None,0,C)
while i<24:
 g=array.array('h',e.read(C));b=sum(map(abs,g))/C
 if b>0 and 20*L(b/32768,10)>A:
  f=G.fftconvolve(g,g[::-1])[C:];d=N.diff(f);s=0
  while d[s]<=0:s+=1
  x=N.argmax(f[s:])+s;u=f[x-1];v=f[x+1]
  if int(12*L(((u-v)/2/(u-2*f[x]+v)+x)*F/C/440,2))==n[i]+15:print(w[i],end='',flush=1);i+=1

这需要...

根据您的麦克风,环境声音的大小,歌曲的响度等,更改顶行的A = -52(最小振幅)。在我的麦克风上,小于-57的声音似乎会引起很多外来噪音大于-49要求您大声播放。

这可能会打很多。我敢肯定,有一些方法可以在单词数组上保存很多字符。这是我第一个使用python编写的简单程序,所以我对这种语言还不太熟悉。

我从https://gist.github.com/endolith/255291窃取了通过自相关进行频率检测的代码

取消高尔夫:

import pyaudio
from array import array
import scipy.signal
import numpy
import math
import sys

MIN_AMPLITUDE = -52
FRAMERATE = 44100

def first(list):
    for i in range(len(list)):
        if(list[i] > 0):
            return i
    return 0

# Based on: https://en.wikipedia.org/wiki/Decibel#Acoustics
def getAmplitude(sig):
    total = 0;
    elems = float(len(sig))
    for x in sig:
        total += numpy.abs(x) / elems
    if(total == 0):
        return -99
    else:
        return 20 * math.log(total / 32768., 10)    

# Based on: https://en.wikipedia.org/wiki/Piano_key_frequencies
def getNote(freq):
    return int(12 * math.log(freq / 440, 2) + 49)

# --------------------------------------------------------------------------
# This is stolen straight from here w/ very slight modifications: https://gist.github.com/endolith/255291
def parabolic(f, x):
    return 1/2. * (f[x-1] - f[x+1]) / (f[x-1] - 2 * f[x] + f[x+1]) + x

def getFrequency(sig):
    # Calculate autocorrelation (same thing as convolution, but with
    # one input reversed in time), and throw away the negative lags
    corr = scipy.signal.fftconvolve(sig, sig[::-1], mode='full')
    corr = corr[len(corr)/2:]

    # Find the first low point
    diffs = numpy.diff(corr)

    # Find the next peak after the low point (other than 0 lag). This bit is
    # not reliable for long signals, due to the desired peak occurring between
    # samples, and other peaks appearing higher.
    # Should use a weighting function to de-emphasize the peaks at longer lags.
    start = first(diffs)
    peak = numpy.argmax(corr[start:]) + start
    return parabolic(corr, peak) * (FRAMERATE / len(sig))
# --------------------------------------------------------------------------

# These are the wrong keys (ie it is detecting middle C as an A), but I'm far too lazy to figure out why.
# Anyway, these are what are detected from the Wikipedia .ogg file:
notes = [73,          66,           64,       66,         68,       69,        71,          73,       66,     68,          69,         71,         66,        68,         69,        71      ] 
words = ["Twinkle, ", "twinkle, ", "little ", "star,\n",  "How I ", "wonder ", "what you ", "are.\n", "Up a", "bove the ", "world so ", "high,\n", "Like a ", "diamond ", "in the ", "sky.\n"]
notes += notes[:8]
words += words[:8]

pa = pyaudio.PyAudio()
stream = pa.open(format=pyaudio.paInt16, channels = 1, rate = FRAMERATE, input = True, frames_per_buffer = 4096)
idx = 0
while(idx < len(notes)):
    # Read signal
    sig = array('h', stream.read(4096))
    if(getAmplitude(sig) > MIN_AMPLITUDE):
        note = getNote(getFrequency(sig))
        if(note == notes[idx]):
            sys.stdout.write(words[idx])
            sys.stdout.flush()
            idx += 1

我为您写了一些语法帮助。检查14-29和80-88行。pastebin.com/W9XSYwMJ
seequ 2014年

@Sieg-太棒了; 谢谢!旧习惯很难打破。
罗伯特·弗雷泽
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.