その2の本体。 関数が文字数制限にひっかかってしまって、さらに分割しました。
def draw_pianoroll(filename): ''' fft を行い、ピアノロール上にドットを描く ''' global wav_chunk global wav_db # ファイルチェック fin = wave.open(filename, 'rb') (_channel, _sampwidth, _framerate, _nframes, _, _) = fin.getparams() print 'channel:%d, samplewidth:%d[byte], framerate:%d[Hz], frames:%d' % (_channel, _sampwidth, _framerate, _nframes) if _channel > 2: print 'モノラル/ステレオのみに対応しています.' return 0 if _sampwidth > 2: print '未対応のデータ並びです.' return 0 dtype = scipy.int16 if _sampwidth == 1: dtype = scipy.int8 # ピアノロール image = create_roll() (img_width, img_height) = image.size draw = ImageDraw.Draw(image) # ピアノロール A4 での座標 pos_a4 = (pf_keywidth + 1) * (pf_inoct * 3 + 9) + 1 + (pf_keywidth / 2) # FFT結果書き込み開始位置 img_start = pf_depth + 1 # dB最大値保持map -80[dB]-0[dB] -> 0-255 if mod_fine: img_max = Image.new('L', image.size, 0) draw_max = ImageDraw.Draw(img_max) def db2pix(db): return int( (min(wav_db_max, max(-80,db)) + 80.0) / 80.0 * 255 ) print 'image:%d x %d, total lines for this songs:%d' % (img_width, img_height, int(_nframes / _framerate / pix_linesec)) # FFT基数 # 平均律の計算は http://en.wikipedia.org/wiki/Piano_key_frequencies を参照 const_nth_key = -49 base_cent_n = -8 base_freqs = [wav_tuning * math.pow(2.0, 1.0/pf_inoct) ** (i + const_nth_key) for i in range(base_cent_n, base_cent_n + pf_inoct)] #base_keys = ['A0 ','A#0','B0 ','C1 ','C#1','D1 ','D#1','E1 ','F1 ','F#1','G1 ','G#1'] base_keys = ['C0 ','C#0','D0 ','D#0','E0 ','F0 ','F#0','G0 ','G#0','A0 ','A#0','B0 '] color_size = 30 color_base = get_hue_color(color_size) # wav_db[dB] <-> -10[dB] # C0からB0の基数で倍音を計算し、オクターブ(バンド?)だけ拾ってみる for base_cnt, base_freq in enumerate(base_freqs): if mod_fine == 0: if base_cnt == 1: break #wav_chunk *= 2 if base_cnt == 2: break # マップ用座標の準備 (周波数 <=> cent(C1~C8) <=> pixel位置) # A4 (const_nth_key) を中心として、その座標からの相対値とする. # C1:N=-45, C8:N=39 # 2の累乗じゃなくなるけど、遅いなりに動作はしているようだ... if mod_fine: wav_chunk = int(_framerate / base_freq + 0.5) print '%s freq:%4.1f, chunk:%4d, ' % (base_keys[base_cnt], base_freq, wav_chunk), oct_cent_n = [const_nth_key + base_cent_n + base_cnt + pf_inoct * i for i in range(0, 10)] min_res = (_framerate / float(wav_chunk)) / wav_tuning cent = [1200.0 * math.log(0.5 * min_res, 2)] + [1200.0 * math.log(i * min_res, 2) for i in range(1, wav_chunk)] pos_cent = [] # pixel位置 # ピアノロールの範囲(C1-B7)で制限 min_cent = 100.0 * -45 - 50 # -45 = C1 max_cent = 100.0 * 38 + 50 # 38 = B7 min_resolut = 100 / pf_keywidth dis_min = 1 dis_max = wav_chunk for cnt in range(0, wav_chunk): if cent[cnt] < min_cent: pos_cent += [-1] # 負数で座標無効 dis_min = cnt continue if cent[cnt] >= max_cent: dis_max = cnt - 1 break cent_n = int(abs(cent[cnt]) / 100.0 + 0.5) # cent_nは-45(C1)~39(C8)のはず if cent[cnt] < 0: cent_n = -cent_n #print cent_n, # Nの値 cent_sub = cent[cnt] - cent_n * 100 # cent_subは-50~49[cent]のはず pix_fluct = int((cent_sub + 50) / min_resolut - pf_keywidth / 2) pos_cent += [pos_a4 + cent_n * (pf_keywidth + 1) + pix_fluct] # オクターブのみ有効 # cent_n が oct_cent_n のどれかに一致しなければオクターブ以外として無効にする if mod_fine: _check = 0 for oct in oct_cent_n: if cent_n == oct: _check = 1 break if _check == 0: pos_cent[len(pos_cent)-1] = -1 # 1FFTあたりの時間比率 cur_linerate = (wav_chunk / float(_framerate)) / pix_linesec # (1-3)に続く </pre>
1-3へ続く
※コメント投稿者のブログIDはブログ作成者のみに通知されます