“Twinkle Twinkle Little Star”에 가사를 인쇄하십시오


24

당신의 목표는 각 음표가 연주 될 때 노래 "Twinkle Twinkle Little Star"에 가사를 인쇄하는 것입니다.

컴퓨터의 마이크에서 메모가 들립니다. 음표의 피치 (길이는 아님)가 올바른 경우 적절한 음절을 인쇄하십시오. 그렇지 않으면 아무것도하지 마십시오. 각 음표의 길이는 0.5 초 이상이며, 음표 사이에 최소 1/4 초의 간격이 있습니다.

여기 에 제공된 악보 와 다음 가사를 사용하십시오. (세로선은 음절을 나타냅니다.)

쌍둥이 | 꼬리, 쌍둥이 | 꼬리, 작은 별,

내가 어떻게 지 냈는지

세상이 너무 높아서

하늘의 다이아몬드처럼.

쌍둥이 | 꼬리, 쌍둥이 | 꼬리, 작은 별,

내가 어떻게 지 냈는지

음악 녹음은 여기 에서 찾을 수 있습니다 .

컴퓨터가 중간 C를 듣고 "Twin"을 인쇄합니다

또 다른 가운데 C가 들리고 "kle"이 인쇄됩니다.

그런 다음 다른 중간 C를 듣고 (잘못된 음표) 아무것도하지 않습니다.

그런 다음 중간 C 위의 G를 듣고 "트윈"등을 인쇄합니다.

규칙

  • 문장 부호는 그림과 같아야합니다.
  • 간격은 표시된 것과 같아야합니다 (공백과 줄 바꿈).
  • 공백은 이전 음절 또는 다음 음절과 함께 인쇄 될 수 있습니다.

2
"노트가 끝나기 전에 인쇄해야한다"는 방법이 있습니까? 1/16 초 음표를 사용하면 해당 시간의 3/4를 샘플링에 전용하더라도 ~ 47ms의 사운드 만 사용할 수 있습니다. 미드 레인지 음표에 대해 매우 어두운 주파수 해상도를 제공합니다.
Geobits

@Geobits 좋은 지적; 나는 그 규칙을 제거했다.
Ypnypn

1
이것은 내가 찾은 오디오 입력을 사용하는 첫 번째 퍼즐입니다! 축하합니다!
찰스가

1
두 반짝임을 구별하기 위해 제목에 철자가 잘못 되었습니까?
Rainbolt

1
테스트 용 오디오 파일에 대한 링크가있을 수 있습니까?
Calvin 's Hobbies

답변:


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

이것은 필요합니다 ...

  • Python 3 (Windows 64 비트에서 3.3으로 테스트 ... theroy의 Mac / Linux에서 작동 해야 함 )
  • PyAudio ( PyAudio 페이지의 Windows 바이너리 패키지가 작동하지 않았으므로 here 에서 Windows 바이너리 패키지를 사용했습니다)
  • SciPy와 NumPy ( 같은 사이트에서 scipy-stack을 사용했습니다 )

마이크, 주변 소리의 양, 노래가 얼마나 큰지 등에 따라 맨 위 줄의 A = -52 (최소 진폭)를 변경합니다. 내 마이크에서 -57 미만이 많은 외부 노이즈를 포착하는 것 같습니다 -49 이상은 매우 큰 소리로 연주해야합니다.

이것은 더 많은 골프를 쳤다; 특히 단어 배열에 많은 문자를 저장할 수있는 방법이 있다고 확신합니다. 이것은 파이썬에서 처음으로 중요하지 않은 프로그램이므로 아직 언어에 익숙하지 않습니다.

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

@Sieg-굉장한; 감사! 오래된 습관은 깨기 어렵다.
Robert Fraser
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.