waveGenerator続き。
和音合成。

#!/usr/bin/env python
import wave, math, array

class waveGenerator():
    def __init__(self,fileName=''):
        if fileName!='':
            self.openFile(fileName)
        else:
            f = None
        self.inc = math.pow(2,1.0/12)
        self.A = 440
        self.scaleFreqMap = {'A':0,'AS':1,'B':2,'C':3,'CS':4,'D':5,'DS':6,
                             'E':7,'F':8,'FS':9,'G':10,'GS':11}
    def openFile(self,fileName):
        self.nchannels = 1
        self.sampwidth = 2
        self.framerate = 44100
        self.nframes = 0
        self.compname = 'NONE'
        self.comptype = 'not compressed'
        self.f = wave.open(fileName,'w')
        self.f.setparams((self.nchannels,self.sampwidth,self.framerate,self.nframes,
                          self.compname,self.comptype))

    def closeFile(self):
        self.f.close()

    def getFreq(self,scale):
        return math.pow(self.inc,self.scaleFreqMap[scale]) * self.A

    def addScale(self,scale,length,volume=15000):
        self.addWave(self.getFreq(scale),length,volume)

    def getWaveArray(self,freq,length,volume=15000.0):
        data = array.array('h')
        a = math.pi * 2.0 * float(freq) / float(self.framerate)
        for i in range(int(self.framerate*length)):
            ft = int(math.sin(a*float(i))*volume)
            data.append(ft)
        return data
        
    def addWave(self,freq,length,volume=15000.0):
        self.f.writeframesraw(self.getWaveArray(freq,length,volume).tostring())

    def addHarmonyWave(self,scales,length,volume=15000.0):
        dataList = []
        for scale in scales:
            freq = self.getFreq(scale)
            dataList.append(self.getWaveArray(freq,length,volume))
        data = array.array('h')
        data.extend([0]*int(length*self.framerate))
        for scaleData in dataList:
            print len(scaleData)
            for ii in range(len(scaleData)):
                ft = data[ii] + scaleData[ii]
                if ft >= 32767: ft = 32767
                if ft <= -32768: ft = -32768
                data[ii] = ft
        self.f.writeframesraw(data.tostring())

    def no9(self):
	w.addScale('E',0.5)
	w.addScale('E',0.5)
	w.addScale('F',0.5)
	w.addScale('G',0.5)
	w.addScale('G',0.5)
	w.addScale('F',0.5)
	w.addScale('E',0.5)
	w.addScale('D',0.5)
	w.addScale('C',0.5)
	w.addScale('C',0.5)
	w.addScale('D',0.5)
	w.addScale('E',0.5)
	w.addScale('E',0.5)
	w.addScale('D',0.5)
	w.addScale('D',0.5)
	w.addWave(0,0.5)
	w.addScale('E',0.5)
	w.addScale('E',0.5)
	w.addScale('F',0.5)
	w.addScale('G',0.5)
	w.addScale('G',0.5)
	w.addScale('F',0.5)
	w.addScale('E',0.5)
	w.addScale('D',0.5)
	w.addScale('C',0.5)
	w.addScale('C',0.5)
	w.addScale('F',0.5)
	w.addScale('E',0.5)
	w.addScale('D',0.5)
	w.addScale('C',0.5)
	w.addScale('C',0.5)
	w.closeFile()

今回もユーザインタフェースは存在しないのでインタプリタ上から。

>>> w = waveGenerator('harmony.wav')
>>> w.addHarmonyWave(('C','E','G'),0.5)
>>> w.closeFile()

こんな感じで使う。
signed shortの最大値とかわかんなかった*1ので決め打ち。
そのうち調べる>俺。

余談だが、このwaveGenerator実際に音声ファイルを出力しても私は音階がわからないので奥さんに聞いてもらってデバッグしている。
奥さん「なんかデジタルなのにずいぶん原始的な確認方法だね」
しょうがないだろ、わかんないんだもん。

さらに余談だが、どーやらいままでシンタックスハイライトの使い方を間違えていた模様。

>|python|

と打たなければならなかったのに

>|Python|

とか書いていたエントリがたくさんあるっぽい。

*1:取得方法が