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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215 |
import sys
from math import cos,pi,log
import getopt
__doc__ = """
Python Data2Scale app for Linux, version 0.1.
author: Jose I. Orlicki
example:
# cat data2scale.py | python data2scale.py -t 0.05 -s harmonic_minor -i
-h --help : this help
-s --scale= : choose scale, pentatonic is default (diatonic, chromatic, natural_minor or harmonic_minor)
-l --length= : choose data length, default is "nibble", other option is "byte"
-i --inverse : inverse endianess, only for nibble, false or true, default false.
-t --time= : in seconds per note, max 0.5 secs.
-u --sustain : sustains the repeated notes.
"""
class _Getch:
"""Gets a single character from standard input. Does not echo to the
screen."""
def __init__(self):
try:
self.impl = _GetchWindows()
except ImportError:
self.impl = _GetchUnix()
def __call__(self): return self.impl()
# begin getch
class _GetchUnix:
def __init__(self):
import tty, sys
def __call__(self):
import sys, tty, termios
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
try:
tty.setraw(sys.stdin.fileno())
ch = sys.stdin.read(1)
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
return ch
class _GetchWindows:
def __init__(self):
import msvcrt
def __call__(self):
import msvcrt
return msvcrt.getch()
getch = _Getch()
# end getch
def freq(fq=4096, bytes=4096):
# fq = bytes = 2046
# fq = fq * float(512) / 7000
ret = ''
for i in range(bytes):
val = float(i) / bytes
myord = int(((cos(pi * fq * val) + 1.0) / 2) * 255)
ret += chr( myord )
return ret
def play_freq(fq, bytes):
open('/dev/dsp','w').write(freq(fq, bytes))
def note(nro_nota, frac=0.125):
data = freq(110 * (2**(1.0/12))**nro_nota )
return data[:int(frac*len(data))]
def play_note(nr_note):
open('/dev/dsp','w').write(note(nr_note))
def notes_demo():
dev = open('/dev/dsp','w')
for i in range(48):
dev.write( note(i, 0.125) )
for i in range(48,0,-1):
dev.write( note(i, 0.125) )
dev.close()
def chromatic_scale(note_nr):
return note_nr
def diatonic_scale(note_nr):
return (note_nr / 7) * 12 + diatonic(note_nr % 7)
def diatonic(note_nr):
diat_map = {0:0, 1:2, 2:4, 3:5, 4:7, 5:9, 6:11}
if note_nr in diat_map:
return diat_map[note_nr]
else:
raise Exception('bad note number!')
def pentatonic_scale(note_nr):
return (note_nr / 5) * 12 + diatonic(note_nr % 5)
def pentatonic(note_nr):
penta_map = {0:0, 1:2, 2:4, 3:7, 4:9}
if note_nr in penta_map:
return penta_map[note_nr]
else:
raise Exception('bad note number!')
def natural_minor_scale(note_nr):
return (note_nr / 7) * 12 + natural_minor(note_nr % 7)
def natural_minor(note_nr):
nm_map = {0:0, 1:2, 2:3, 3:5, 4:7, 5:8, 6:10}
if note_nr in nm_map:
return nm_map[note_nr]
else:
raise Exception('bad note number!')
def harmonic_minor_scale(note_nr):
return (note_nr / 7) * 12 + harmonic_minor(note_nr % 7)
def harmonic_minor(note_nr):
hm_map = {0:0, 1:2, 2:3, 3:5, 4:7, 5:9, 6:10}
if note_nr in hm_map:
return hm_map[note_nr]
else:
raise Exception('bad note number!')
buffer = []
def data_music(data, scale_func=chromatic_scale, frac=0.125, length='byte', inverse=False, sustain=False):
global buffer
dev = open('/dev/dsp','w')
notes = ''
for char in data:
if length == 'nibble':
fst = ord(char) >> 4
snd = ord(char) & ord('\x0f')
if not inverse:
buffer.append(fst)
if len(buffer)>1 and buffer[-1]!=buffer[-2]:
dev.write( note( scale_func( buffer[-2] ), frac ) * (len(buffer)-1))
buffer = buffer[-1:]
buffer.append(snd)
else:
buffer.append(snd)
if len(buffer)>1 and buffer[-1]!=buffer[-2]:
dev.write( note( scale_func( buffer[-2] ), frac ) * (len(buffer)-1))
buffer = buffer[-1:]
buffer.append(fst)
else:
n = ord(char) / 1
buffer.append(n)
if len(buffer)>1 and buffer[-1]!=buffer[-2]:
dev.write( note( scale_func( buffer[-2] ), frac ) * (len(buffer)-1))
buffer = buffer[-1:]
dev.close()
#data_music('AAAAAAAAAA')
def main():
# parse command line options
try:
opts, args = getopt.getopt(sys.argv[1:], "hs:l:it:u", ["help","scale","length","inverse","time","sustain"])
# process options
scale, length, time, inverse, sustain = pentatonic_scale, 'nibble', 0.2, False, False
scale_map = {
'pentatonic':pentatonic_scale,
'diatonic':diatonic_scale,
'natural_minor':natural_minor_scale,
'harmonic_minor':harmonic_minor_scale,
'chromatic':chromatic_scale,
}
for o, a in opts:
if o in ("-h", "--help"):
print __doc__
sys.exit(0)
elif o in ("-s", "--scale"):
scale = scale_map[a]
elif o in ("-l", "--length"):
length = a
elif o in ("-i", "--inverse"):
inverse = True
elif o in ("-t", "--time"):
time = float(a) * 2.0
elif o in ("-u", "--sustain"):
sustain = True
else:
raise Exception('Unknown parameter!: %s' % o)
while True:
try:
char = getch()
except Exception, e:
char = sys.stdin.read(1)
if not char: break
data_music( char, scale, time, length, inverse, sustain )
except getopt.error, msg:
print msg
print "for help use --help"
sys.exit(2)
except Exception, e:
print 'Bad something: ' + str(e)
print "for help use --help or -h"
if __name__ == "__main__":
main()
|