pyDoper.py

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import numpy
from numpy import sin,cos,abs,pi,random,array
from scikits.audiolab import Format,Sndfile,play
from sys import argv,exit
from optparse import OptionParser
'''Output iDoser-like sound to sound device(Linux Alsa and some MacOS) or to
file
\t%prog [options] [target.file.flac]'''
def optioner(argv=argv[1:]):
parser = OptionParser(usage=__doc__)
parser.add_option('-f','--freq',
action="store", dest='f0', type='float', default=90,
help='main tone frequency')
parser.add_option('-d','--diftone',
action="store", dest='df', type='float',default=3,
help='pseudo tone frequency')
parser.add_option('-r','--rate',
action="store", dest='rate', type='int', default=48000,
help='sampling frequence (must be supported by your device)')
parser.add_option('-t','--time',
action="store", dest='time', type='int', default=60,
help='time to play')
parser.add_option('-n','--noisetype',
action="store", dest='noisy', default='white',
help='Type of noise (white or pink)')
parser.add_option('-l','--noiselevel',
action="store", dest='level', type='float', default=0.005,
help='level of noise')
parser.add_option('-v','--verbose',
action="store_true", dest='verbose', default=False,
help='be verbose')
(o,args) = parser.parse_args(argv)
return (o,args)
def normalise(ar,Am=1,statistical=False):
if statistical:
return Am * ar/abs(ar.mean()+ar.std())
else:
return Am * ar/abs(ar).max()
def noise(time,a=0.01,rate=48000,noisy=random.standard_normal):
length = rate*time
n = noisy(size=length)
if noisy==random.standard_normal:
n = a*n
else:
n = normalise(n,a,True)
return array([n,n])
def actualise(freq,rate=48000):
'''Убедиться, что все периоды звучат одинаково'''
return rate *1./int(rate/freq)
def generator(f1,f2,time,rate):
length = time*rate
koef = 2*pi/rate
tone = lambda fx:\
[sin(koef*fx*x) for x in xrange(length)]
return array([tone(f1), tone(f2)])
def main(args):
(o,target) = optioner()
## шумы:
# random.standard_normal — похож на белый шум
# random.lognormal — похож на "розовый" шум
if o.noisy=='pink':
noiseType = random.lognormal
elif o.noisy=='none':
noiseType = False
else:
noiseType = random.standard_normal
if noiseType:
base = noise(o.time, o.level, o.rate, noiseType)
else:
null = [0 for i in xrange(o.time*o.rate)]
base = array([null,null])
f1 = actualise(o.f0)
f2 = actualise(f1+o.df)
final = generator(f1,f2,o.time,o.rate)
final = normalise(final+base)
#final = abs(base)
if o.verbose:
print 'True base freq: %f Hz'%f1
print 'Difference freq: %f hz'%(f2-f1)
print 'Defined noise level',abs(base[1]).mean()
print '* Starting to play'
if target:
fmt = Format()
f = Sndfile(target[0],'w',fmt,2,o.rate)
f.write_frames(
array([ [final[0][i],final[1][i]] for i in xrange(len(final[0])) ])
)
else:
play(final,o.rate)
if o.verbose:
print '* Finished playing'
if __name__ == "__main__":
exit(main(argv))