程序猿的音乐世界-Extempore

来源:互联网 发布:万网域名管理登录 编辑:程序博客网 时间:2024/04/28 04:46

程序猿的音乐世界

你或许听过有人拿着ipad的现场演奏,但你或许么听说过现场敲代码的现场演奏,今年的OSCON上Andrew Sorensen给我们带来了一些新奇—Extempore,concert programmers,用code的音乐现场。

YOUTUBE视频:Andrew SorensenOSCON 2014 Keynote: "The Concert Programmer"。

视频在土豆网也有转载http://www.tudou.com/programs/view/2o_ChSqo984/。

13年在TedX的视频:ComputeMusic(now):Andrew Sorensen at TEDxQUT

Github:https://github.com/digego/extempore

一、   安装方法:

1.     Extempore

如果你使用的OSX系统,使用homebrew安装将会很简单

brew tapbenswift/extemporebrewinstall extempore

如果是linux的话则需要自己编译源码

Window下安装会比较麻烦点,官方教程里说需要

Visual Studio Express 2012 for WindowsDesktopCMakegit7zip (or equivalent) for uncompressingfiles

依赖包有PCRE,Portaudio,LLVM,Boost库。

为了省事,我是使用的OSX系统下安装的。

2.     运行

安装完后进入extempore的安装目录,我的安装目录是

/usr/local/Cellar/extempore/0.53

运行

./extempore


Extempore是一个实时的lisp解释运行程序,我们要运行自己的代码,需要使用tcp连接到extempore的服务上,这里有一个现成的sublime插件

https://github.com/benswift/extempore-sublime

安装完这个插件在sublime里使用快捷键CTRL+X+Y连接server,

选中需要运行的代码使用快捷键CTRL+X+X将代码发送到extempore,sublime的左下角会显示连接结果,运行结果也将出现在左下角。


 

3.     代码

至于Andrew在现场演示的代码可以在github上找到,另外需要配置一些音频文件,包括常用的钢琴(gound piano),架子鼓,贝斯。具体操作步骤如下:

$ git clonehttps://gist.github.com/8b4404e538e61c7996a5.git$ cd 8b4404e538e61c7996a5$ mkdir salamander && cd salamander$ curl -L -O https://archive.org/download/SalamanderDrumkit/salamanderDrumkit.tar.bz2$ curl -L -Ohttps://github.com/johnsen/drumsandpercussion/blob/master/SalamanderKick/salamanderdrum-kick-r1.tar.gz$ curl -L -Ohttp://freepats.zenvoid.org/Piano/SalamanderGrandPianoV3_44.1khz16bit.tar.bz2$ tar xvfz salamanderDrumkit.tar.bz2$ tar xvfz salamanderdrum-kick-r1.tar.gz$ mv Kick/kick* OH/$ tar xvfzSalamanderGrandPianoV3_44.1khz16bit.tar.bz2 $ brew tap benswift/extempore$ brew install extempore$ cd /usr/local/Cellar/extempore/0.52$ ./extempore


4.     示例

Extempore 的代码是以xtm后缀名的文件,用sublime打开会自动识别语法。装载现有的xtm格式的lib可以使用sys:load加载,比如

(sys:load"libs/core/instruments.xtm")

首先我们需要装载音频的sample文件

比如装载鼓的音频文件:

;;;定义加载函数<br style="box-sizing: border-box;" />(define add-drum-sample<br style="box-sizing: border-box;" />(lambda (file-name const-name)<br style="box-sizing: border-box;" />(set-sampler-index drums<br style="box-sizing: border-box;" />(string-append drum-pathfile-name)<br style="box-sizing: border-box;" />const-name<br style="box-sizing: border-box; color: rgb(199, 37, 78); font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 14px; letter-spacing: 0.360000014305115px; line-height: 24.4799995422363px; white-space: nowrap;" />0 0 0 1)))<br style="box-sizing: border-box;" />;;;定义音频<br style="box-sizing: border-box;" />(define drum-sample-data<br style="box-sizing: border-box;" />(list<br style="box-sizing: border-box;" />(list "kick_OH_F_9.wav" *gm-kick*)<br style="box-sizing: border-box;" />(list "hihatClosed_OH_F_20.wav" *gm-closed-hi-hat*)<br style="box-sizing: border-box;" />(list "hihatFoot_OH_MP_12.wav" *gm-pedal-hi-hat*)<br style="box-sizing: border-box; color: rgb(199, 37, 78); font-family: Menlo, Monaco, Consolas, 'Courier New', monospace; font-size: 14px; letter-spacing: 0.360000014305115px; line-height: 24.4799995422363px; white-space: nowrap;" />(list "hihatOpen_OH_FF_6.wav" *gm-open-hi-hat*)))<br style="box-sizing: border-box;" />;;;批量加载函数<br style="box-sizing: border-box;" />(define add-drum-samples<br style="box-sizing: border-box;" />(lambda (data)<br style="box-sizing: border-box;" />(map (lambda (sample-pair)<br style="box-sizing: border-box;" />(add-drum-sample (car sample-pair) (cadr sample-pair)))<br style="box-sizing: border-box;" />data)))<br style="box-sizing: border-box;" />;;;执行加载函数<br style="box-sizing: border-box;" />(add-drum-samples drum-sample-data)

这样我们就加载完鼓的音频资源文件了。

使用

;;;低音大鼓(play-note (now) drums *gm-kick* 180 44100)
<p>;;;镲片</p><p>(play-note (now) drums *gm-open-hi-hat* 14044100)</p>

同理我们可以加载钢琴,贝斯等资源文件。

然后定义音符

(define base-note 12) (define get-note (lambda (octave offset)   (+ (* base-note octave) offset))) (define C1 (get-note 1 0))(define C2 (get-note 2 0))(define C3 (get-note 3 0))(define C4 (get-note 4 0))(define C5 (get-note 5 0))(define C6 (get-note 6 0))(define C7 (get-note 7 0)) (define D1 (get-note 1 2))(define D2 (get-note 2 2))(define D3 (get-note 3 2))(define D4 (get-note 4 2))(define D5 (get-note 5 2))(define D6 (get-note 6 2))(define D7 (get-note 7 2))…
Andrew在现场演示时候直接使用数字,这里定义成大调音阶这样的形式,比较方便辨识。

钢琴左手:

;;;定义左手弹奏的音符(define left-hand-notes-2 (list G4 G4 A4B4));;;定义弹奏的函数(define left-hand (lambda (beat ps ds)    (play piano (car ps) 170 (* 2.0 (car ds)))   (callback (*metro* (+ beat (* .95 (car ds)))) 'left-hand (+ beat (cards))              (rotate ps -1)              (rotate ds -1))));;;执行左手弹奏(left-hand (*metro* 'get-beat 4)left-hand-notes-2 (list 1))

<p>钢琴右手</p>
(define right-hand (lambda (beat dur)   (play piano         (pc:quantize (cosr (+ root C2) (cosr 5 3 1/2) 7/3) scale)         (cosr 160 20 7/3)         (* 4.0 dur))   (callback (*metro* (+ beat (* .5 dur))) 'right-hand (+ beat dur) dur))) (right-hand (*metro* 'get-beat 4) 1/4)

鼓:

(define kick (lambda (beat dur)   (play drums 35 150 dur)   (callback (*metro* (+ beat (* .5 dur))) 'kick (+ beat dur) dur))) (kick (*metro* 'get-beat 4) 1)

镲片:

(define hats (lambda (beat dur)   (play drums (random '(44 42)) (cosr 80 60 (random '(7/3 5/2))) dur)   (callback (*metro* (+ beat (* .5 dur))) 'hats (+ beat dur) dur))) (hats (*metro* 'get-beat 4) 1/4)

二、   Extempore的语法

Extempore差不多算是一个比较成熟的实时的编译环境,它的编程语言叫xtlang,一种特制的类lisp语言,如果你觉得上面的代码看起来看不懂的话,可以看看lisp的入门资料,xtlang和scheme的语法比较相近,但是它是强类型的,同时引入了很多C语言的特性,保留了lisp的函数式编程的基本特性。底层使用LLVM作为它的compiler。

1.   基本类型:

整型:

i1 (boolean)

i8 (char)

i32

i64 (default)

 

float型:

float (32 bit)

double (64 bit, default)

 

指针:

double*: a pointer to a double

i64**: a pointer to a pointer to a 64-bitinteger

 

集合类型:

元组Tuples

Arrays

Vectors

Closure type

如果写过C++,python应该不难理解这些容器的使用

2.   内存管理:

Xtlang中的scheme对象在被销毁或没有引用的时候会被GC自动回收,用户也可以像C/C++那样在堆栈上手动分配内存。

extempore的内存分配函数包括salloc, halloc 和 zalloc。

这三个函数的作用都是申请一块内存并返回一个指针,区别在于分配的内存区域不同,salloc在stack中申请内存, zalloc从当前内存区域分配内存,有点类似于salloc,但是这里要引入一个memory zone的概念。

官方解释是:

Zone allocation is kindof like stackallocation, except with user control over when the memory is freed (as opposedit happening at the end of function execution, as with memory on the stack).Essentially this means that we can push and pop zones off of a stack of memoryzones of user-defined size.

Halloc是从heap中分配内存,。Zalloc还有一个别名alloc。官方文档说三个函数以内存生命周期来理解这三个函数,但是我觉得这样的说法好像有点欠妥。

(bind-funcptr_test
  (lambda()
    (let((a:double*(zalloc)))
      (printf"address = %p\n" a))))
 
(ptr_test);; prints "address = 0x1163bc030"

上面是一个zalloc的使用示例,定义一个闭包函数ptr_test,打印zalloc函数分配的内存地址。

 

3.   其他

另外xtlang还可以引入c语言库,对音频DSP也有很多的支持环境,可以播放虚拟MIDI乐器,具体介绍可以参考http://benswift.me/extempore-docs/,有兴趣的同学可以多看看。

和extempore相似的语言还有一个斯坦福的gewang开发的chuck,但extempore是异步的,chuck是同步的,区别如下:

//synchronous timing
play-note(now)
time =(now)+44100
play-note(now)
 
//asynchronous timing
play-note(now)
play-note(now+44100)

 

0 0
原创粉丝点击