用 Python 把电脑变钢琴

  录一段音频,把它的音高改变50次并把每一个新的音频匹配到键盘的一个键位,你就能把电脑变成一架钢琴!

  一段音频可以被编码为一组数值的数组(或者列表),像这样:

  

  我们可以在数组中每隔一秒拿掉一秒的值来将这段音频的速度变成两倍:

  

  如此我们不仅将音频的长度减半了,而且我们还将它的频率翻倍了,这样使得它拥有比原来更高的音高(pitch)。

  相反地,假如我们将数组中每个值重复一次,我们将得到一段更慢,周期更长,即音高更低的音频:

  

  这里提供一个可以按任意系数改变音频速度的任意简单的Python函数:

  Python

  1

  2

  3

  4

  5

  6

  7import numpy as np

  def speedx(sound_array, factor):

  """ 将音频速度乘以任意系数`factor` """

  indices = np.round( np.arange(0, len(snd_array), factor) )

  indices = indices[indices < len(snd_array)].astype(int)

  return sound_array[ indices.astype(int) ]

  这个问题更困难的地方在于改变音频长度的同时保持它的音高(变速,音频拉伸(sound stretching)),或者在改变音频的音高的同时保持它的长度(变调(pitch shifting))。

  变速

  变速可以通过传统的相位声码器(phase vocoder,感兴趣的朋友可以读一下维基百科的页面)来实现。首先将音频分解成重叠的比特,然后将这些比特重新排列使得他们重叠得更多(将缩短声音的长度)或者更少(将拉伸音频的长度),如下图所示:

  

  困难之处在于重新排列的比特可能很严重的互相影响,那么这里就需要用到相位变换来确保它们之间没有影响。这里有一段Python代码,取自这个网页(打不开的话,您懂的。——译者注):

  Python

  1

  2

  3

  4

  5

  6

  7

  8

  9

  10

  11

  12

  13

  14

  15

  16

  17

  18

  19

  20

  21

  22

  23

  24

  25

  26def stretch(sound_array, f, window_size, h):

  """ 将音频按系数`f`拉伸 """

  phase = np.zeros(window_size)

  hanning_window = np.hanning(window_size)

  result = np.zeros( len(sound_array) /f + window_size)

  for i in np.arange(0, len(sound_array)-(window_size+h), h*f):

  # 两个可能互相重叠的子数列

  a1 = sound_array[i: i + window_size]

  a2 = sound_array[i + h: i + window_size + h]

  # 按第一个数列重新同步第二个数列

  s1 = np.fft.fft(hanning_window * a1)

  s2 = np.fft.fft(hanning_window * a2)

  phase = (phase + np.angle(s2/s1)) % 2*np.pi

  a2_rephased = np.fft.ifft(np.abs(s2)*np.exp(1j*phase))

  # 加入到结果中

  i2 = int(i/f)

  result[i2 : i2 + window_size] += hanning_window*a2_rephased

  result = ((2**(16-4)) * result/result.max()) # 归一化 (16bit)

  return result.astype(‘int16‘)

  变调

  一旦你实现了变速以后,变调就不难了。如果需要一个更高的音高,可以先将这段音频拉伸并保持音高不变,然后再加快它的速度,如此最后得到的音频将具有原始音频同样的长度,更高的频率,即更高的音高。

  把一段音频的频率翻倍将把音高提高一个八度,也就是12个半音。因此,要将音高提高n个半音的话,我们需要将频率乘上系数2^(n/12):

  Python

  1

  2

  3

  4

  5def pitchshift(snd_array, n, window_size=2**13, h=2**11):

  """ 将一段音频的音高提高``n``个半音 """

  factor = 2**(1.0 * n / 12.0)

  stretched = stretch(snd_array, 1.0/factor, window_size, h)

  return speedx(stretched[window_size:], factor)

  小程序:电脑钢琴

  让我们来玩一下我们的变调器。我们先敲碗来确定一个“标准音高”:

  接下来我们基于之前的音频创造50个变调的音高,从很低到很高:

  Python

  1

  2

  3

  4

  5from scipy.io import wavfile

  fps, bowl_sound = wavfile.read("bowl.wav")

  tones = range(-25,25)

  transposed = [pitchshift(bowl_sound, n) for n in tones]

  接下来根据这个文件中的顺序,我们把每一个音频匹配到键盘的一个键位,如下图所示:

  

  我们只需要在代码中告诉计算机当一个键按下来的时候播放其对应的声音,然后当按键松开后停止播放就可以了:

  Python

  1

  2

  3

  4

  5

  6

  7

  8

  9

  10

  11

  12

  13

  14

  15

  16

  17

  18

  19

  20

  21

  22

  23

  24

  25

  26

  27

  28

  29

  30

  31

  32

  33

  34import pygame

  pygame.mixer.init(fps, -16, 1, 512) # 太灵活了 ;)

  screen = pygame.display.set_mode((640,480)) # 设置焦点

  # 得到键盘的键位的正确顺序的列表

  # ``keys`` 如 [‘Q‘,‘W‘,‘E‘,‘R‘ ...] 一样排列

  keys = open(‘typewriter.kb‘).read().split(‘\n‘)

  sounds = map(pygame.sndarray.make_sound, transposed)

  key_sound = dict( zip(keys, sounds) )

  is_playing = {k: False for k in keys}

  while True:

  event = pygame.event.wait()

  if event.type in (pygame.KEYDOWN, pygame.KEYUP):

  key = pygame.key.name(event.key)

  if event.type == pygame.KEYDOWN:

  if (key in key_sound.keys()) and (not is_playing[key]):

  key_sound[key].play(fade_ms=50)

  is_playing[key] = True

  elif event.key == pygame.K_ESCAPE:

  pygame.quit()

  raise KeyboardInterrupt

  elif event.type == pygame.KEYUP and key in key_sound.keys():

  key_sound[key].fadeout(50) # 停止播放并50ms淡出

  is_playing[key] = False

  就这样我们把计算机变成了一台钢琴!至此,让我为您表演一段土耳其进行曲来表达对您耐心阅读此文的谢意吧:

  如果想自己试试的话,在这里可以下载你需要的所有文件。因为不是所有的人都用Python,我也用Javascript/HTML5(在这儿)实现了一台电脑钢琴,但是不是特别理想。如果有经验丰富的HTML5/JS/elm程序员来改进改进,或者从头重写就太好了。

  接下来做什么?

  更通常的情况下,我发现计算机很少被用来进行表演性质的演奏。我明白使用钢琴键盘或者直接从乐器录音会容易很多,但是请看看仅仅用一个碗和60行的Python代码就能做到什么!

  即便是很便宜的计算机也有如此多的控制来实现一个马马虎虎的音乐台:你可以对着麦克风唱歌,对着摄像头做手势,用鼠标来调制,然后用键盘来完成剩下来的玩意儿。有如此多方式来表现自我,而每种方式又有那么一个Python包……有没有具有艺术天赋的大神加入呀?

时间: 2024-07-29 00:38:17

用 Python 把电脑变钢琴的相关文章

最近开发电脑变得异常慢的原因和解决

感觉电脑配置也不差,有8G内存,就最近几天,变得异常得慢,甚至保存一个txt文件都卡几十秒,查了电脑的虚拟内存,找到了原因,原来的虚拟内存是电脑自动管理 (当前使用虚拟内存达到了 8G),时间久了,越来越大,就越来越卡了. 解决办法如下: 按提示重启电脑,就会好很多,我电脑也不卡了!ok. 经验:如果内存条容量大,够用,尽量不要使用虚拟内存,使用虚拟内存的话会使电脑变慢很多. 这个方法或许针对所有的windows系统都有用,不信你可以试一下你的电脑,哈哈.

电脑变慢了怎么变快?教你从软硬件两个方面搞定它!

电脑变慢了怎么变快?教你从软硬件两个方面搞定它! 谁都希望计算机一开机就可以立即进入Windows 系统而不用等待,或者是系统在使用的时候不会越来越慢,但由于种种原因常常使这些愿望不能实现,甚至一开机就死机或者用着用着就越来越慢的情况也经常发生.其实有些时候Windows 启动速度缓慢并不是它本身的问题,而是一些设备或软件造成的.本文就是软件.硬件和病毒三大方面来分析系统速度变慢的原因,并且提供了针对系统的加速技巧. 一.软件篇 1.设定虚拟内存 硬盘中有一个很宠大的数据交换文件,它是系统预留给

python制作电脑定时关机办公神器,另含其它两种方式,无需编程!

小编本人目前就是在电脑面前工作,常常会工作到凌晨两三点还在为自己的梦想奋斗着.有时在办公椅上就稀里糊涂睡着了,我相信有很多朋友和我一样,这样是很不好的.第一对身体不好,第二对电脑不好. 对身体方面,小编也只能说大家年轻的时候千万要对自己好点,特别是在电脑面前工作的朋友,不然以后身体毛病变多,就很难受了.像我才二十多岁,现在坐两个小时就会背部发麻,股椎那里也有轻微疼痛,所以各位朋友千万要注意这一点. 对电脑不好,虽然你已经没有在使用它,但是电脑却一直在工作,CUP一直在运转,它就像我们的人脑一直在

python远程控制电脑

python拥有大量的第三方库,且语法简单.今天老杨就用python实现远程控制电脑 ? 所谓,谋定而后动,在实现任何一个需求之前,我们需要先分析,捋清楚一个思路,远程控制电脑,无非就是接收远程的命令和根据命令去执行对应的操作.那这里,我们借助微信来接收命令,利用我们的一个itchat库实现远程控制电脑 ? 按上所说,我们要完成需求,无非是把任务细分,首先,接收到消息指令,再根据对应的指令执行相对应的操作,其中我们需要考虑一个问题就是误触问题. ? python有大量的第三方库,这里我们借助it

python 录制电脑声音

只录制麦克风.只录制扬声器.同时录制麦克风和扬声器 python实现录制声音功能相关包有Pyaudio和sounddevice,这两者只能实现录制电脑麦克风输入的的声音,不能录制扬声器输出的声音... 我想只录制扬声器的声音,结果没实现,好气哦 pyaudio好像是有解决办法的 https://stackoverflow.com/questions/26573556/record-speakers-output-with-pyaudio 原文地址:https://www.cnblogs.com/

python+opencv 电脑调用手机的摄像头

移动端下载一个工具:IP摄像头(app) Android的下载地址:http://app.mi.com/details?id=com.shenyaocn.android.WebCam 下载安装后,打开app后,点击下方的"打开IP摄像头服务器"(连上wifi,确保电脑与手机处在同一局域网内). 然后,使用python进行opencv代码调用部分: import cv2 cv2.namedWindow("camera",1) #开启ip摄像头 video="

【翻译】如何通过使用两台电脑变得更加有效率

本篇文章已经被我在译言翻译发表,如需转载请注明作者和原始链接:点击打开链接 原来标题:How to become more productive by using 2 computers 原作者:Amir Salihefendic (作者是Doist的创始人,是 Todoist和Wedoist软件的作者.) 原始链接:http://amix.dk/blog/post/19722 我有一个简单明确的关于提高工作效率的方法要与你们分享. 我注意到一件事情(特别是在我处理难题的时候),例如我打开邮件,

物理内存使用率偏高,电脑变卡常见原因

转载自:百度知道 1.硬件存在兼容性问题BIOS,设置不正确 重新设置BIOS2.灰尘过多 清理机箱保持内部干燥干净3.msconfig下关闭不必要的程序CPU或内存配置低 (更换CPU添加内存)4.硬盘存在逻辑或物理坏道 (找专业人士检修或更换)5.CPU温度过高 更换大功率风扇 保持室内通风良好6.电源电压不稳 买个稳压器或UPS电源7.开启的程序过多 内存被大量占用 结束不必要的程序8.若是怀疑自己电脑深层次有病毒或者木马,可以使用腾讯电脑管家将电脑木马清理出来9.垃圾文件过多 碎片文件过

小知识:Python函数传递变长

先来实践一把: def f1(*args): print(args) f1(1,2,3,4) 得出:(1, 2, 3, 4) ----- 是一个元祖 Part 1: *args可以传递任意多的数,args返回的是一个元祖,可迭代 如果要传入一个列表或元祖,变成多个参数传递,比方说我输入[1,2,3,4],传入到f1变成f1(1,2,3,4)四个参数 def f1(*args): print(args) f1([1,2,3,4]) 得出:([1,2,3,4],), 如果我这么做传入的只是一个参数,