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

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

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

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

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

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

import 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代码,取自这个网页(打不开的话,您懂的。——译者注):

def 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):

def 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)

小程序:电脑钢琴

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

[youku id="XNzM1NDM2NTky"]

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

from scipy.io import wavfile

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

tones = range(-25,25)

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

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

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

import 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

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

[youku id="XNzM1NDQ1MDA4"]

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

接下来做什么?

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

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

python制作简单软件_用Python制作简单的钢琴程序的教程相关推荐

  1. python制作电脑软件_利用PYTHON制作桌面版爬虫软件(一)

    抱歉,对长沙房地产数据的挖掘与分析[三],想了蛮久,觉得对自己的分析结果不是很理想.等我完善好了,我再发出来吧.今天继续开启新的一专题.主要讲解如何用PYTHON实现简单的桌面软件的制作. 题外话,我 ...

  2. python实现数据恢复软件_恢复python

    centos 7 python2.7.5升级到3.5.2 centos 7 python2.7.5升级到3.5.2 下载python3.5.2 wget https://www.python.org/ ...

  3. python 爬取软件_用Python爬取了三大相亲软件评论区,结果...

    小三:怎么了小二?一副愁眉苦脸的样子. 小二:唉!这不是快过年了吗,家里又催相亲了 ... 小三:现在不是流行网恋吗,你可以试试相亲软件呀. 小二:这玩意靠谱吗? 小三:我也没用过,你自己看看软件评论 ...

  4. python 工资管理软件_基于[Python]的员工管理系统

    基于[Python]的员工管理系统 -------------------------------- 简介 使用python语言来完成一个员工管理系统,员工信息包含:员工工号,姓名, 年龄,性别,职位 ...

  5. python制作电脑软件_利用PYTHON制作桌面版爬虫软件(二)

    今天继续新的专题.主要讲解[利用PYTHON制作桌面版爬虫软件]下的如何实现界面功能(一).该讲主要包括以下三个内容:掌握如何编写主函数,运行界面. 了解pywin32模块. 如何用python识别Q ...

  6. python设计答题软件_用python制作《冲顶大会》答题工具

    最近很多人玩答题类App,例如冲顶大会.芝士超人.百万英雄系列,答对12道题与其他玩家平分所有奖金,虽然奖金没有刚开始的时候多了,但偶尔还是能有个饭钱的.一方面是玩的人多了,另一方面是因为科技手段太多 ...

  7. python图片水印软件_基于Python制作的控制鼠标删除图片水印的小工具

    在做视频或者图片处理的时候,我们经常会遇到存在水印的情况,或者我们需要去除图片的某一个部分, 这时候我们就需要想办法去除不需要的这一部分.下面这个工具能够控制鼠标将图片上的任意部分改变颜色, 从而达到 ...

  8. python图片水印软件_使用Python编写批量添加图片水印程序:一、代码方案

    一.为什么要为图片添加水印 在互联网写文章最头疼的一件事情就是发表的文章容易被抄袭,各种抄袭的手段真的是层出不穷.无奈,只能在不影响阅读体验的情况下不断地提高反抄袭的难度.虽然防不住,但是为文章中的图 ...

  9. python 表格处理软件_基于Python的Excel处理工具

    1项目描述# #的辛勤工作,以减少处理Excel在我姐姐的工作中,我写了一些代码处理xlsx在python中独立完成一些任务,如判断未来的列表,晚了,每天和早期离开根据考勤记录,并实现两个细胞的比较复 ...

最新文章

  1. DLL延迟加载工程分析
  2. 工作利用NUnit进行调试
  3. 西贝莜面村员工手册_西贝那达慕草原美食节 引领文化生活新消费
  4. linux搭建压力测试,安装GTKStressTesting:对Linux系统进行压力测试变得更加容易
  5. 服务器互相备份不同步_详解容灾与备份,为数据安全保驾护航
  6. 我所理解的性能测试是什么?
  7. 这个 80 后 IT 男厉害了!他用北京蜗居的首付在东京海淘了一栋楼!
  8. 工业互联网联盟发布工业物联网安全框架
  9. 在线文本按列截取工具
  10. python后端和爬虫_【后端开发】python爬虫难学吗
  11. The Innovation | 谁是蛋白质和核酸的失踪的“媒人”?
  12. 用ZeroTier搭建属于自己的虚拟局域网(VLAN)
  13. c语言parse是什么意思英语,it/parse是什么意思
  14. 自己动手写一个小型的TCP/IP协议
  15. 你们要的《一曲相思》附下载
  16. Python自动化:根据模板批量生成含指定数据的word文档
  17. win10开机占用内存大,资源管理器也看不到运行进程
  18. 水泥caement英语
  19. 三、Qt常用容器之QList
  20. 蜂窝网实现移动性管理?

热门文章

  1. 业余爱好者,想做自己厂的ERP软件
  2. 【原创】suhunbsp;视频
  3. 如何在今日头条号上做产品引流?今日头条引流实际操作技巧
  4. ipmi重启_超微(SuperMicro)服务器的IPMI/iKVM使用方法(开机,关机,重启,重装系统)...
  5. 淘宝天猫商家运营推广,宝贝点击率、展现量有什么作用
  6. w3c创建就web标准 例如html,WEB编程基础-中国大学mooc-题库零氪
  7. 【niubi-job——一个分布式的任务调度框架】----框架设计原理以及实现
  8. matlab元组转化为举证,[转载]基于MATLAB对有限元模型进行转化
  9. Android搜狗输入法搜索栏
  10. iOS App启动广告