Iromono


※上記の広告は60日以上更新のないWIKIに表示されています。更新することで広告が下部へ移動します。

Iromonoへのメモ。

pythonのmixerを利用して。

1.8からbufferを使えるようになったので、

struct.packした文字列をbufferオブジェクトにして流す。

デフォルトでは符号付き16bitデータになっているので、

short型にする。

import pygame
import struct
import math
import time

def dub(dub_tone,dub_time=5,vol=3000,wave=math.sin):
  st =time.time()
  pygame.mixer.init()
  bd = pygame.mixer.Sound('se.wav')
  newbuf=''
  freq = 22050
  for i in range(freq*dub_time*2):
    newbuf += struct.pack('h',wave(i*dub_tone/float(freq)) * vol)
  s = pygame.mixer.Sound(buffer(newbuf))
  s.play()
  '''for c in bd.get_buffer():
  print c,'''
  pygame.time.wait(dub_time*1000)
  print 'end:%f'%(time.time()-st)

if __name__=='__main__':
  def rect(t):
    t=abs(t-int(t))
    if t < 0.5:
      return 1.0
    else:
      return -1.0
  def sin_wave(t):
    t=abs(t-int(t))
    return math.sin(t*2*math.pi)

  dub(440,wave=sin_wave)

1周期のみのループで試す。

1周期の波を出して、それをチャンネルでループさせる。

\frac{freq}{tone} = 1周期のサンプリング数

なので、wave(t)関数(ただし  0 &lt; t &lt;= 1 )を利用して一応サンプリングできる。


もちろん無理やりにつないでいるのでノイズが乗る。

#toneを貰って1周期の波形を作る
#coding:utf-8
import pygame
import math
import array

def sinwave(t):
  t=abs(t-int(t))
  return math.sin(t*2*math.pi)

#toneを貰って1周期の波形を作る
def makewave(tone,freq=22050,wave=sinwave,vol=3000):
  buff = array.array('h')
  if tone == 0:
    buff.append(0)
    buff.append(0)
    return pygame.mixer.Sound(buff)
  maxstep = freq/tone
  for t in xrange(maxstep):
    buff.append(int(wave( t * 1/float(maxstep))*vol))
  return pygame.mixer.Sound(buff)

#上記のsinwaveを利用して
def dub(tone,time):
  sound = makewave(tone)
  cnl = pygame.mixer.Channel(0)
  cnl.play(sound,loops=-1)
  pygame.time.delay(time)
  cnl.stop()

def test_func():
  pygame.mixer.init()
  music=((440,1000),(0,1000),(440,500),(480,300),(520,250))
  for tone,time in music:
    dub(tone,time)

if __name__=='__main__':
  test_func()

僕の耳アカがたまってるせいか、440,500の音が気のせいか短く感じる。

Beepの時にも試したけど、1オクターブは2倍音。

 octave(tone) =&gt; 2*tone

これを12等分の等比数列にするので、12乗根を取る。

 nexttone(tone) =&gt; (2*tone)^{1/12}

440回りの前後50の音階を得るには次のプログラムを走らせる。

for x in xrange(100):
  print math.pow(2,1/12.0)**(x-50)*440

dubtest.py

import math
import array
from fmwave import make_fmfunc

def make_rectfunc(duty=0.5):
  def rectwave(t):
    t=abs(t-int(t))
    return 1.0 if t<duty else -1.0
  return rectwave

def sinwave(t):
  t=abs(t-int(t))
  return math.sin(t*2*math.pi)

#toneを貰って1周期の波形を作る
def makewave(tone,wave,freq=22050,vol=3000):
  buff = array.array('h')
  if tone == 0:
    buff.append(0)
    buff.append(0)
    return pygame.mixer.Sound(buff)
  maxstep = int(freq/tone)
  for t in xrange(maxstep):
    buff.append(int(wave( t * 1/float(maxstep))*vol))
  return pygame.mixer.Sound(buff)

#上記のsinwaveを利用して
def dub(tone,time,wave):
  sound = makewave(tone,wave)
  cnl = pygame.mixer.Channel(0)
  cnl.play(sound,loops=-1)
  pygame.time.delay(time)
  cnl.stop()

def test_func():
  pygame.mixer.init()
  wave = make_rectfunc(0.5)#make_fmfunc(220,440,100)
  tone_range=20
  for x in xrange(tone_range*2):
    tone = math.pow(2,1/12.0)**(x-tone_range)*440
    dub(tone,1000,wave)

if __name__=='__main__':
  test_func()

fmwave.py

import math

def make_fmfunc(career,modulator,fm_param,):
  def fm_wave(t):
    modwave = fm_param*math.sin(t*math.pi*2*modulator)
    return math.sin(career*2*math.pi*t+modwave)
  return fm_wave

def wave_test():
  wave1 = make_fmfunc(220,440,1)
  for t in xrange(32):
    print(wave1(t * 1/32.0))

if __name__=='__main__':
  wave_test()

wikipediaのFM音源の式をそのまま書いたもの。

http://ja.wikipedia.org/wiki/FM%E9%9F%B3%E6%BA%90

音がだいぶ違う気がする。(気のせいじゃない)

気づいたこと:

FM音源はキャリアを周波数変換するので、

基本音源の音階はキャリアに指定するもんだということがわかる。

つまりcareerを現状きめうちしているが、

これを2引数を取る関数にしたい。


def make_fmfunc2(modulator,fm_param):
  def fm_wave(t,career):
    modwave = fm_param*math.sin(t*math.pi*2*modulator)
    return math.sin(career*2*math.pi*t+modwave)
  return fm_wave

こうするとtが0.0-1.0の間が一周期とは単純にいえなくなりそう。

ほかのRectとかでも考えたい。

iromono_in_cpp