shlisp_tools 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +119 -0
- data/Rakefile +7 -0
- data/bin/shlerb +47 -0
- data/bin/shtool +235 -0
- data/examples/hexanies.txt.erb +103 -0
- data/examples/metaslendro.txt.erb +63 -0
- data/lib/shlisp_tools/ratio.rb +81 -0
- data/lib/shlisp_tools/scale.rb +83 -0
- data/lib/shlisp_tools/scales.rb +47 -0
- data/lib/shlisp_tools/shnth.rb +31 -0
- data/lib/shlisp_tools/version.rb +3 -0
- data/lib/shlisp_tools.rb +5 -0
- data/shlisp_tools.gemspec +24 -0
- metadata +113 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 DaveSeidel
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
# ShlispTools
|
2
|
+
|
3
|
+
Tools for shlisp/shnth developers. If you don't recognize both of words starting with "sh", this is probably not for you.
|
4
|
+
|
5
|
+
Executables:
|
6
|
+
* shlerb (a templating and uploading tool for txts; an ERB wrapper for shlisp)
|
7
|
+
* shtool (a collection of little calculations)
|
8
|
+
|
9
|
+
Classes/Modules:
|
10
|
+
* ShlispTools::Ratio # represents a pitch ratio
|
11
|
+
* ShlispTools::Scales # represents a scale (consisting of Ratios)
|
12
|
+
* ShlispTools::Scales # tiny collection of predefined scales
|
13
|
+
* ShlispTools::Shnth # useful constants and macros for Shnth things
|
14
|
+
|
15
|
+
Shlerb code samples in examples directory.
|
16
|
+
|
17
|
+
Shlisp & Shnth come from Sbobo - http://shbobo.net
|
18
|
+
|
19
|
+
## Installation
|
20
|
+
|
21
|
+
Add this line to your application's Gemfile:
|
22
|
+
|
23
|
+
gem 'shlisp_tools'
|
24
|
+
|
25
|
+
And then execute:
|
26
|
+
|
27
|
+
$ bundle
|
28
|
+
|
29
|
+
Or install it yourself as:
|
30
|
+
|
31
|
+
$ gem install shlisp_tools
|
32
|
+
|
33
|
+
## Usage
|
34
|
+
|
35
|
+
Shlerb usage:
|
36
|
+
|
37
|
+
shlerb FILENAME
|
38
|
+
|
39
|
+
where FILENAME is something like cool_shnth_patches.txt.erb or cool_shnth_patches.shlerb. The contents of the file should be shlisp code with optional ERB sections containing Ruby code. (For more information on ERB, see https://en.wikipedia.org/wiki/ERuby). The Ruby code has access to the modules and classes mentioned above. More details soon.
|
40
|
+
|
41
|
+
What shlerb does: it translates the input file into pure shlisp code and then uploads it to the attached Shnth using the "shlisp" command (from http://shbobo.net). If these are error translating the file, the error is displayed and nothing is uploaded.
|
42
|
+
|
43
|
+
## Examples
|
44
|
+
|
45
|
+
Here's an example of a shlerb file with a single situation. It plays a six-note meta-slendro scale on the keys in the order majora, majorb, majorc, majord, minord, minorc. The tones fade in slowly and will tend to (intentionally) distort as they reach full amplitude. The scale used is part of the collection of pre-defined scales that come with ShlispTools.
|
46
|
+
|
47
|
+
<%
|
48
|
+
Slew_mul = 5
|
49
|
+
Slew_add = 5
|
50
|
+
Modo_mul = 2
|
51
|
+
%>
|
52
|
+
<% s1 = Scales::MetaSlendro_1.scale(120) %>
|
53
|
+
{
|
54
|
+
<%= Shnth::Situation_1 %>
|
55
|
+
|
56
|
+
; 60Hz-ish
|
57
|
+
(srate (short 72 79))
|
58
|
+
|
59
|
+
(arab
|
60
|
+
|
61
|
+
(pan
|
62
|
+
(add
|
63
|
+
(modo (horna <%= s1[Shnth::Bar_A].n %> <%= s1[Shnth::Bar_A].d %> (slewa (majora) <%= Slew_mul %> <%= Slew_add %>)) <%= Modo_mul %>)
|
64
|
+
(modo (hornc <%= s1[Shnth::Bar_C].n %> <%= s1[Shnth::Bar_C].d %> (slewc (majorc) <%= Slew_mul %> <%= Slew_add %>)) <%= Modo_mul %>)
|
65
|
+
(modo (horne <%= s1[Shnth::Bar_d].n %> <%= s1[Shnth::Bar_d].d %> (slewe (minord) <%= Slew_mul %> <%= Slew_add %>)) <%= Modo_mul %>)
|
66
|
+
)
|
67
|
+
144
|
68
|
+
)
|
69
|
+
|
70
|
+
(pan
|
71
|
+
(add
|
72
|
+
(modo (hornb <%= s1[Shnth::Bar_B].n %> <%= s1[Shnth::Bar_B].d %> (slewb (majorb) <%= Slew_mul %> <%= Slew_add %>)) <%= Modo_mul %>)
|
73
|
+
(modo (hornd <%= s1[Shnth::Bar_D].n %> <%= s1[Shnth::Bar_D].d %> (slewd (majord) <%= Slew_mul %> <%= Slew_add %>)) <%= Modo_mul %>)
|
74
|
+
(modo (hornf <%= s1[Shnth::Bar_c].n %> <%= s1[Shnth::Bar_c].d %> (slewf (minorc) <%= Slew_mul %> <%= Slew_add %>)) <%= Modo_mul %>)
|
75
|
+
)
|
76
|
+
80
|
77
|
+
)
|
78
|
+
|
79
|
+
)
|
80
|
+
}
|
81
|
+
|
82
|
+
You can also define your own scales and add a scaling factor to bring them into the right range for your srate.
|
83
|
+
|
84
|
+
<%
|
85
|
+
|
86
|
+
# shortcuts for long names
|
87
|
+
S = ShlispTools::Scale
|
88
|
+
R = ShlispTools::Ratio
|
89
|
+
|
90
|
+
# define scale with 1/1 = 100 100
|
91
|
+
myMetaSlendro = S::Scale.new([
|
92
|
+
R::Ratio.new( 1, 1),
|
93
|
+
R::Ratio.new(37, 32),
|
94
|
+
R::Ratio.new(21, 16),
|
95
|
+
R::Ratio.new(49, 32),
|
96
|
+
R::Ratio.new( 7, 4),
|
97
|
+
R::Ratio.new( 2, 1)
|
98
|
+
]).scale(100)
|
99
|
+
|
100
|
+
# get nume and deno for a given scale degree, using indexes 0 through 5 for a six-note scale
|
101
|
+
# 1/1:
|
102
|
+
# myMetaSlendro[0].nume
|
103
|
+
# myMetaSlendro[0].deno
|
104
|
+
#
|
105
|
+
# 37/32
|
106
|
+
# myMetaSlendro[1].nume
|
107
|
+
# myMetaSlendro[1].deno
|
108
|
+
#
|
109
|
+
# ...
|
110
|
+
|
111
|
+
%>
|
112
|
+
|
113
|
+
## Contributing
|
114
|
+
|
115
|
+
1. Fork it
|
116
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
117
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
118
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
119
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/bin/shlerb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'erb'
|
4
|
+
|
5
|
+
require 'shlisp_tools'
|
6
|
+
|
7
|
+
# for the binding
|
8
|
+
Scales = ShlispTools::Scales
|
9
|
+
Shnth = ShlispTools::Shnth
|
10
|
+
|
11
|
+
def error(s)
|
12
|
+
puts s
|
13
|
+
exit 1
|
14
|
+
end
|
15
|
+
|
16
|
+
class Shlerb
|
17
|
+
|
18
|
+
TEMP_FILE = "_shlerb_temp"
|
19
|
+
|
20
|
+
def self.perform(infile)
|
21
|
+
template_file = File.open(infile, 'r').read
|
22
|
+
out = nil
|
23
|
+
|
24
|
+
begin
|
25
|
+
out = herb(template_file)
|
26
|
+
rescue Exception => e
|
27
|
+
# do again and show verbos output
|
28
|
+
$VERBOSE = true
|
29
|
+
puts herb(template_file)
|
30
|
+
exit 1
|
31
|
+
end
|
32
|
+
|
33
|
+
if out
|
34
|
+
File.open(TEMP_FILE, 'w+') { |f| f.write(out) }
|
35
|
+
system("shlisp #{TEMP_FILE}")
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
def self.herb(tmpl)
|
41
|
+
ERB.new(tmpl, nil, ">").result(binding)
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
error "usage: shlerb FILENAME" if ARGV.length < 1
|
47
|
+
Shlerb.perform(ARGV[0])
|
data/bin/shtool
ADDED
@@ -0,0 +1,235 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
#------------------------------------------------------------------------------
|
4
|
+
# ops
|
5
|
+
#------------------------------------------------------------------------------
|
6
|
+
|
7
|
+
class OpResult
|
8
|
+
attr_reader :args, :result
|
9
|
+
|
10
|
+
def initialize(args=nil, result=nil)
|
11
|
+
@args = args
|
12
|
+
@result = result
|
13
|
+
end
|
14
|
+
|
15
|
+
def get
|
16
|
+
{ :args => @args, :result => @result }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# base class for operations
|
21
|
+
class Op
|
22
|
+
def self.name
|
23
|
+
""
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.get(args)
|
27
|
+
OpResult.new.get
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.usage(err=nil)
|
31
|
+
puts "#{name} error: #{err}" if err
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.description
|
35
|
+
""
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
def self.parse_ratio(txt)
|
40
|
+
parsed = {}
|
41
|
+
matches = /(\d+)[\/\:](\d+)/.match(txt)
|
42
|
+
if matches && matches.captures.length >= 2
|
43
|
+
parsed[:nume] = matches[1].to_i
|
44
|
+
parsed[:deno] = matches[2].to_i
|
45
|
+
end
|
46
|
+
parsed
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# operations
|
51
|
+
|
52
|
+
class OpSr < Op
|
53
|
+
CLOCK = 72000000.0
|
54
|
+
|
55
|
+
def self.name
|
56
|
+
"sr"
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.description
|
60
|
+
"given args for short to be passed to srate, computes resulting base pitch"
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.get(args)
|
64
|
+
if args.length < 2
|
65
|
+
usage "too few args"
|
66
|
+
else
|
67
|
+
OpResult.new(args,
|
68
|
+
impl(args)
|
69
|
+
).get
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.usage(err=nil)
|
74
|
+
super err
|
75
|
+
puts "#{name} args: bigg smal"
|
76
|
+
puts description
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
def self.impl(args)
|
81
|
+
(CLOCK / ((args[0].to_i * 256) + args[1].to_i)).round(2)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
class OpRatMul < Op
|
86
|
+
def self.name
|
87
|
+
"mul"
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.description
|
91
|
+
"given a ratio in nume/deno form, applies a multiplier to both sides (for scaling)"
|
92
|
+
end
|
93
|
+
|
94
|
+
def self.get(args)
|
95
|
+
if ARGV.length < 2
|
96
|
+
usage "too few args"
|
97
|
+
else
|
98
|
+
parts = parse_ratio(ARGV[0])
|
99
|
+
if parts.empty?
|
100
|
+
usage "bad args"
|
101
|
+
else
|
102
|
+
OpResult.new(args,
|
103
|
+
impl(parts, args[1].to_i)
|
104
|
+
).get
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def self.usage(err=nil)
|
110
|
+
super err
|
111
|
+
puts "#{name} args: nume/deno mul"
|
112
|
+
puts description
|
113
|
+
end
|
114
|
+
|
115
|
+
private
|
116
|
+
def self.impl(parts, mul)
|
117
|
+
[parts[:nume] * mul, parts[:deno] * mul]
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
class OpRange < Op
|
122
|
+
Min = -128
|
123
|
+
Max = 128
|
124
|
+
|
125
|
+
def self.name
|
126
|
+
"range"
|
127
|
+
end
|
128
|
+
|
129
|
+
def self.description
|
130
|
+
"given a mul and an add, computes the resulting range as [low, nominal, high]"
|
131
|
+
end
|
132
|
+
|
133
|
+
def self.get(args)
|
134
|
+
if args.length < 2
|
135
|
+
usage "too few args"
|
136
|
+
else
|
137
|
+
OpResult.new(args,
|
138
|
+
impl(args[0].to_i, args[1].to_i)
|
139
|
+
).get
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
def self.usage(err=nil)
|
144
|
+
super err
|
145
|
+
puts "#{name} args: nume deno"
|
146
|
+
puts description
|
147
|
+
end
|
148
|
+
|
149
|
+
private
|
150
|
+
def self.impl(mul, add)
|
151
|
+
lo = ((Min * mul) / Max) + add
|
152
|
+
hi = ((Max * mul) / Max) + add
|
153
|
+
[lo, add, hi]
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
class OpReduce < Op
|
158
|
+
def self.name
|
159
|
+
"reduce"
|
160
|
+
end
|
161
|
+
|
162
|
+
def self.description
|
163
|
+
"given a ratio in nume/deno form, computes the reduced version"
|
164
|
+
end
|
165
|
+
|
166
|
+
def self.get(args)
|
167
|
+
if args.length < 1
|
168
|
+
usage "too few args"
|
169
|
+
else
|
170
|
+
parts = parse_ratio(ARGV[0])
|
171
|
+
if parts.empty?
|
172
|
+
usage "bad args"
|
173
|
+
else
|
174
|
+
OpResult.new(args,
|
175
|
+
impl(parts)
|
176
|
+
).get
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
def self.usage(err=nil)
|
182
|
+
super err
|
183
|
+
puts "#{name} args: nume/deno"
|
184
|
+
puts description
|
185
|
+
end
|
186
|
+
|
187
|
+
private
|
188
|
+
def self.impl(parts)
|
189
|
+
r = Rational(parts[:nume], parts[:deno])
|
190
|
+
[r.numerator, r.denominator]
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
# known operations
|
195
|
+
Ops = [ OpSr, OpRatMul, OpRange, OpReduce ]
|
196
|
+
|
197
|
+
#------------------------------------------------------------------------------
|
198
|
+
# mainline code
|
199
|
+
#------------------------------------------------------------------------------
|
200
|
+
|
201
|
+
def usage
|
202
|
+
puts "usage: 'shtool OP [args ...]'"
|
203
|
+
puts "where OP is one of: #{Ops.collect{ |op| op.name}.join(" ") }"
|
204
|
+
puts "or try 'shtool help'"
|
205
|
+
exit 1
|
206
|
+
end
|
207
|
+
|
208
|
+
def main(argv)
|
209
|
+
if argv.length < 1
|
210
|
+
usage
|
211
|
+
else
|
212
|
+
op = argv.shift
|
213
|
+
case op
|
214
|
+
when "help"
|
215
|
+
Ops.each { |op| puts "#{op.name}: #{op.description}" }
|
216
|
+
when "sr"
|
217
|
+
sr = OpSr.get(argv)
|
218
|
+
puts "(srate (short #{sr[:args][0]} #{sr[:args][1]})) = #{sr[:result]}" if sr
|
219
|
+
when "mul"
|
220
|
+
mul = OpRatMul.get(argv)
|
221
|
+
puts "#{mul[:args][0]} * #{mul[:args][1]} -> #{mul[:result][0]}/#{mul[:result][1]}" if mul
|
222
|
+
when "range"
|
223
|
+
range = OpRange.get(argv)
|
224
|
+
puts "#{range[:args][0]} #{range[:args][1]} -> [#{range[:result].join(",")}]" if range
|
225
|
+
when "reduce"
|
226
|
+
reduce = OpReduce.get(argv)
|
227
|
+
puts "#{reduce[:args][0]} -> #{reduce[:result][0]}/#{reduce[:result][1]}" if reduce
|
228
|
+
else
|
229
|
+
puts "Unrecognized operation #{op}"
|
230
|
+
usage
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
main(ARGV)
|
@@ -0,0 +1,103 @@
|
|
1
|
+
<%
|
2
|
+
Slew_mul = 5
|
3
|
+
Slew_add = 5
|
4
|
+
Modo_mul = 2
|
5
|
+
%>
|
6
|
+
<% s = Scales::Hexany1357.scale(127) %>
|
7
|
+
{
|
8
|
+
<%= Shnth::Situation_1 %>
|
9
|
+
|
10
|
+
; 60Hz-ish
|
11
|
+
(srate (short 36 79))
|
12
|
+
|
13
|
+
(arab
|
14
|
+
|
15
|
+
(pan
|
16
|
+
(add
|
17
|
+
(modo (horna <%= s[Shnth::Bar_A].n %> <%= s[Shnth::Bar_A].d %> (slewa (majora) <%= Slew_mul %> <%= Slew_add %>)) <%= Modo_mul %>)
|
18
|
+
(modo (hornc <%= s[Shnth::Bar_C].n %> <%= s[Shnth::Bar_C].d %> (slewc (majorc) <%= Slew_mul %> <%= Slew_add %>)) <%= Modo_mul %>)
|
19
|
+
(modo (horne <%= s[Shnth::Bar_d].n %> <%= s[Shnth::Bar_d].d %> (slewe (minord) <%= Slew_mul %> <%= Slew_add %>)) <%= Modo_mul %>)
|
20
|
+
(modo (horng <%= s[Shnth::Bar_b].n %> <%= s[Shnth::Bar_b].d %> (slewg (minorb) <%= Slew_mul %> <%= Slew_add %>)) <%= Modo_mul %>)
|
21
|
+
)
|
22
|
+
80
|
23
|
+
)
|
24
|
+
|
25
|
+
(pan
|
26
|
+
(add
|
27
|
+
(modo (hornb <%= s[Shnth::Bar_B].n %> <%= s[Shnth::Bar_B].d %> (slewb (majorb) <%= Slew_mul %> <%= Slew_add %>)) <%= Modo_mul %>)
|
28
|
+
(modo (hornd <%= s[Shnth::Bar_D].n %> <%= s[Shnth::Bar_D].d %> (slewd (majord) <%= Slew_mul %> <%= Slew_add %>)) <%= Modo_mul %>)
|
29
|
+
(modo (hornf <%= s[Shnth::Bar_c].n %> <%= s[Shnth::Bar_c].d %> (slewf (minorc) <%= Slew_mul %> <%= Slew_add %>)) <%= Modo_mul %>)
|
30
|
+
(modo (hornh <%= s[Shnth::Bar_a].n %> <%= s[Shnth::Bar_a].d %> (slewh (minora) <%= Slew_mul %> <%= Slew_add %>)) <%= Modo_mul %>)
|
31
|
+
)
|
32
|
+
144
|
33
|
+
)
|
34
|
+
|
35
|
+
)
|
36
|
+
}
|
37
|
+
|
38
|
+
{
|
39
|
+
<%= Shnth::Situation_2 %>
|
40
|
+
|
41
|
+
; 60Hz-ish
|
42
|
+
(srate (short 72 79))
|
43
|
+
|
44
|
+
(arab
|
45
|
+
|
46
|
+
(corpb 60 60)
|
47
|
+
|
48
|
+
(pan
|
49
|
+
(comba
|
50
|
+
(add
|
51
|
+
(modo (sawa <%= s[Shnth::Bar_A].n %> <%= s[Shnth::Bar_A].d %> (slewa (majora) <%= Slew_mul %> <%= Slew_add %>)) <%= Modo_mul %>)
|
52
|
+
(modo (sawc <%= s[Shnth::Bar_C].n %> <%= s[Shnth::Bar_C].d %> (slewc (majorc) <%= Slew_mul %> <%= Slew_add %>)) <%= Modo_mul %>)
|
53
|
+
(modo (sawe <%= s[Shnth::Bar_d].n %> <%= s[Shnth::Bar_d].d %> (slewe (minord) <%= Slew_mul %> <%= Slew_add %>)) <%= Modo_mul %>)
|
54
|
+
(modo (sawg <%= s[Shnth::Bar_b].n %> <%= s[Shnth::Bar_b].d %> (slewg (minorb) <%= Slew_mul %> <%= Slew_add %>)) <%= Modo_mul %>)
|
55
|
+
)
|
56
|
+
120 (corpb) 100
|
57
|
+
)
|
58
|
+
80
|
59
|
+
)
|
60
|
+
|
61
|
+
(pan
|
62
|
+
(combb
|
63
|
+
(add
|
64
|
+
(modo (sawb <%= s[Shnth::Bar_B].n %> <%= s[Shnth::Bar_B].d %> (slewb (majorb) <%= Slew_mul %> <%= Slew_add %>)) <%= Modo_mul %>)
|
65
|
+
(modo (sawd <%= s[Shnth::Bar_D].n %> <%= s[Shnth::Bar_D].d %> (slewd (majord) <%= Slew_mul %> <%= Slew_add %>)) <%= Modo_mul %>)
|
66
|
+
(modo (sawf <%= s[Shnth::Bar_c].n %> <%= s[Shnth::Bar_c].d %> (slewf (minorc) <%= Slew_mul %> <%= Slew_add %>)) <%= Modo_mul %>)
|
67
|
+
(modo (sawh <%= s[Shnth::Bar_a].n %> <%= s[Shnth::Bar_a].d %> (slewh (minora) <%= Slew_mul %> <%= Slew_add %>)) <%= Modo_mul %>)
|
68
|
+
)
|
69
|
+
120 (corpb) 100
|
70
|
+
)
|
71
|
+
144
|
72
|
+
)
|
73
|
+
|
74
|
+
)
|
75
|
+
|
76
|
+
}
|
77
|
+
|
78
|
+
{
|
79
|
+
<%= Shnth::Situation_3 %>
|
80
|
+
|
81
|
+
(left
|
82
|
+
(waveb
|
83
|
+
(add
|
84
|
+
(modo (sawa 20 60 (saucec 56 (slewa (bara) 8 24))) 2)
|
85
|
+
(modo (sawb 30 60 (sauced 60 (slewb (barb) 8 24))) 2)
|
86
|
+
)
|
87
|
+
24
|
88
|
+
(corp 10 60)
|
89
|
+
)
|
90
|
+
)
|
91
|
+
|
92
|
+
(right
|
93
|
+
(wavec
|
94
|
+
(add
|
95
|
+
(modo (sawc 40 60 (saucee 70 (slewc (barc) 8 24))) 2)
|
96
|
+
(modo (sawd 80 60 (saucef 64 (slewd (bard) 8 24))) 2)
|
97
|
+
)
|
98
|
+
24
|
99
|
+
(corpb 10 60)
|
100
|
+
)
|
101
|
+
)
|
102
|
+
|
103
|
+
}
|
@@ -0,0 +1,63 @@
|
|
1
|
+
<%
|
2
|
+
Slew_mul = 5
|
3
|
+
Slew_add = 5
|
4
|
+
Modo_mul = 2
|
5
|
+
%>
|
6
|
+
<% s1 = Scales::MetaSlendro_1.scale(120) %>
|
7
|
+
{
|
8
|
+
<%= Shnth::Situation_1 %>
|
9
|
+
|
10
|
+
; 60Hz-ish
|
11
|
+
(srate (short 72 79))
|
12
|
+
|
13
|
+
(arab
|
14
|
+
|
15
|
+
(pan
|
16
|
+
(add
|
17
|
+
(modo (horna <%= s1[Shnth::Bar_A].n %> <%= s1[Shnth::Bar_A].d %> (slewa (majora) <%= Slew_mul %> <%= Slew_add %>)) <%= Modo_mul %>)
|
18
|
+
(modo (hornc <%= s1[Shnth::Bar_C].n %> <%= s1[Shnth::Bar_C].d %> (slewc (majorc) <%= Slew_mul %> <%= Slew_add %>)) <%= Modo_mul %>)
|
19
|
+
(modo (horne <%= s1[Shnth::Bar_d].n %> <%= s1[Shnth::Bar_d].d %> (slewe (minord) <%= Slew_mul %> <%= Slew_add %>)) <%= Modo_mul %>)
|
20
|
+
)
|
21
|
+
144
|
22
|
+
)
|
23
|
+
|
24
|
+
(pan
|
25
|
+
(add
|
26
|
+
(modo (hornb <%= s1[Shnth::Bar_B].n %> <%= s1[Shnth::Bar_B].d %> (slewb (majorb) <%= Slew_mul %> <%= Slew_add %>)) <%= Modo_mul %>)
|
27
|
+
(modo (hornd <%= s1[Shnth::Bar_D].n %> <%= s1[Shnth::Bar_D].d %> (slewd (majord) <%= Slew_mul %> <%= Slew_add %>)) <%= Modo_mul %>)
|
28
|
+
(modo (hornf <%= s1[Shnth::Bar_c].n %> <%= s1[Shnth::Bar_c].d %> (slewf (minorc) <%= Slew_mul %> <%= Slew_add %>)) <%= Modo_mul %>)
|
29
|
+
)
|
30
|
+
80
|
31
|
+
)
|
32
|
+
|
33
|
+
)
|
34
|
+
}
|
35
|
+
<% s2 = Scales::MetaSlendro_2.scale(120) %>
|
36
|
+
{
|
37
|
+
<%= Shnth::Situation_2 %>
|
38
|
+
|
39
|
+
; 60Hz-ish
|
40
|
+
(srate (short 72 79))
|
41
|
+
|
42
|
+
(arab
|
43
|
+
|
44
|
+
(pan
|
45
|
+
(add
|
46
|
+
(modo (horna <%= s2[Shnth::Bar_A].n %> <%= s2[Shnth::Bar_A].d %> (slewa (majora) <%= Slew_mul %> <%= Slew_add %>)) <%= Modo_mul %>)
|
47
|
+
(modo (hornc <%= s2[Shnth::Bar_C].n %> <%= s2[Shnth::Bar_C].d %> (slewc (majorc) <%= Slew_mul %> <%= Slew_add %>)) <%= Modo_mul %>)
|
48
|
+
(modo (horne <%= s2[Shnth::Bar_d].n %> <%= s2[Shnth::Bar_d].d %> (slewe (minord) <%= Slew_mul %> <%= Slew_add %>)) <%= Modo_mul %>)
|
49
|
+
)
|
50
|
+
144
|
51
|
+
)
|
52
|
+
|
53
|
+
(pan
|
54
|
+
(add
|
55
|
+
(modo (hornb <%= s2[Shnth::Bar_B].n %> <%= s2[Shnth::Bar_B].d %> (slewb (majorb) <%= Slew_mul %> <%= Slew_add %>)) <%= Modo_mul %>)
|
56
|
+
(modo (hornd <%= s2[Shnth::Bar_D].n %> <%= s2[Shnth::Bar_D].d %> (slewd (majord) <%= Slew_mul %> <%= Slew_add %>)) <%= Modo_mul %>)
|
57
|
+
(modo (hornf <%= s2[Shnth::Bar_c].n %> <%= s2[Shnth::Bar_c].d %> (slewf (minorc) <%= Slew_mul %> <%= Slew_add %>)) <%= Modo_mul %>)
|
58
|
+
)
|
59
|
+
80
|
60
|
+
)
|
61
|
+
|
62
|
+
)
|
63
|
+
}
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module ShlispTools
|
2
|
+
class Ratio
|
3
|
+
include Enumerable
|
4
|
+
|
5
|
+
attr_reader :nume, :deno, :rat
|
6
|
+
|
7
|
+
def initialize(nume, deno, scale=nil)
|
8
|
+
@nume = nume
|
9
|
+
@deno = deno
|
10
|
+
_set_rat
|
11
|
+
scale(scale)
|
12
|
+
end
|
13
|
+
|
14
|
+
# pos: scale up (multiply)
|
15
|
+
# neg: scale down (divide)
|
16
|
+
def scale(mul)
|
17
|
+
if mul
|
18
|
+
if mul >= 0
|
19
|
+
@nume *= mul
|
20
|
+
@deno *= mul
|
21
|
+
@nume = 255 if @nume > 255
|
22
|
+
@deno = 255 if @deno > 255
|
23
|
+
else
|
24
|
+
mul = mul.abs
|
25
|
+
@nume /= mul
|
26
|
+
@deno /= mul
|
27
|
+
@nume = 1 if @nume <= 0
|
28
|
+
@deno = 1 if @deno <= 0
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def n
|
34
|
+
@nume
|
35
|
+
end
|
36
|
+
|
37
|
+
def n=(nume)
|
38
|
+
@nume = nume
|
39
|
+
_set_rat
|
40
|
+
end
|
41
|
+
|
42
|
+
def d
|
43
|
+
@deno
|
44
|
+
end
|
45
|
+
|
46
|
+
def d=(deno)
|
47
|
+
@deno = deno
|
48
|
+
_set_rat
|
49
|
+
end
|
50
|
+
|
51
|
+
def reduce
|
52
|
+
Ratio.new(@rat.numerator, @rat.denominator)
|
53
|
+
end
|
54
|
+
|
55
|
+
def reduce!
|
56
|
+
@nume = @rat.numerator
|
57
|
+
@deno = @rat.denominator
|
58
|
+
end
|
59
|
+
|
60
|
+
def to_s
|
61
|
+
"#{@nume}/#{@deno}"
|
62
|
+
end
|
63
|
+
|
64
|
+
def to_r
|
65
|
+
@rat
|
66
|
+
end
|
67
|
+
|
68
|
+
def each
|
69
|
+
yield @rat
|
70
|
+
end
|
71
|
+
|
72
|
+
def <=>(other)
|
73
|
+
@rat <=> other.rat
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
def _set_rat
|
78
|
+
@rat = Rational(@nume, @deno)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module ShlispTools
|
2
|
+
class Scale
|
3
|
+
include Enumerable
|
4
|
+
|
5
|
+
DEF_SEP = ' '
|
6
|
+
|
7
|
+
def initialize(degrees=nil)
|
8
|
+
@degrees = []
|
9
|
+
if degrees && !degrees.empty?
|
10
|
+
degrees.each { |n| @degrees << n }
|
11
|
+
_sort
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def add(degree)
|
16
|
+
@degrees << degree
|
17
|
+
_sort
|
18
|
+
end
|
19
|
+
|
20
|
+
def remove(idx)
|
21
|
+
@degrees.delete_at(idx) rescue nil
|
22
|
+
end
|
23
|
+
|
24
|
+
def scale(mul)
|
25
|
+
unless empty?
|
26
|
+
@degrees.each_with_index do |note,i|
|
27
|
+
if i == 0
|
28
|
+
note.scale(mul)
|
29
|
+
else
|
30
|
+
tmp = ((mul > note.deno) ? mul : mul*2)
|
31
|
+
note.scale((tmp / note.deno).to_i)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
self
|
36
|
+
end
|
37
|
+
|
38
|
+
def [](idx)
|
39
|
+
@degrees[idx] rescue nil
|
40
|
+
end
|
41
|
+
|
42
|
+
def length
|
43
|
+
@degrees.length
|
44
|
+
end
|
45
|
+
|
46
|
+
def empty?
|
47
|
+
@degrees.empty?
|
48
|
+
end
|
49
|
+
|
50
|
+
def <<(degree)
|
51
|
+
add(degree)
|
52
|
+
end
|
53
|
+
|
54
|
+
def each(&block)
|
55
|
+
@degrees.each(&block)
|
56
|
+
end
|
57
|
+
|
58
|
+
def to_s
|
59
|
+
scaled
|
60
|
+
end
|
61
|
+
|
62
|
+
def scaled(sep=DEF_SEP)
|
63
|
+
@degrees.inject([]) { |out,d| out << d.to_s; out }.join(sep)
|
64
|
+
end
|
65
|
+
|
66
|
+
def reduced(sep=DEF_SEP)
|
67
|
+
@degrees.inject([]) { |out,d| out << d.to_r.to_s; out }.join(sep)
|
68
|
+
end
|
69
|
+
|
70
|
+
def numes(sep=DEF_SEP)
|
71
|
+
@degrees.inject([]) { |out,d| out << d.n; out }.join(sep)
|
72
|
+
end
|
73
|
+
|
74
|
+
def denos(sep=DEF_SEP)
|
75
|
+
@degrees.inject([]) { |out,d| out << d.d; out }.join(sep)
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
def _sort
|
80
|
+
@degrees.sort!
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'shlisp_tools/scale'
|
2
|
+
|
3
|
+
module ShlispTools
|
4
|
+
module Scales
|
5
|
+
|
6
|
+
# 1-3-5-7 hexany, utonal stellated
|
7
|
+
# second degree (49/48) and 2/1 removed to fit eight buttons
|
8
|
+
Hexany1357 = Scale.new([
|
9
|
+
Ratio.new( 1, 1),
|
10
|
+
Ratio.new(25, 24),
|
11
|
+
Ratio.new( 7, 6),
|
12
|
+
Ratio.new( 5, 4),
|
13
|
+
Ratio.new(35, 24),
|
14
|
+
Ratio.new( 3, 2),
|
15
|
+
Ratio.new( 5, 3),
|
16
|
+
Ratio.new( 7, 4)
|
17
|
+
])
|
18
|
+
|
19
|
+
MetaSlendro_1 = Scale.new([
|
20
|
+
Ratio.new( 1, 1),
|
21
|
+
Ratio.new(37, 32),
|
22
|
+
Ratio.new(21, 16),
|
23
|
+
Ratio.new(49, 32),
|
24
|
+
Ratio.new( 7, 4),
|
25
|
+
Ratio.new( 2, 1)
|
26
|
+
])
|
27
|
+
|
28
|
+
MetaSlendro_2 = Scale.new([
|
29
|
+
Ratio.new( 1, 1),
|
30
|
+
Ratio.new( 9, 8),
|
31
|
+
Ratio.new(151, 128),
|
32
|
+
Ratio.new( 3, 2),
|
33
|
+
Ratio.new( 25, 16),
|
34
|
+
Ratio.new( 2, 1)
|
35
|
+
])
|
36
|
+
|
37
|
+
CentaurPelog = Scale.new([
|
38
|
+
Ratio.new( 1, 1),
|
39
|
+
Ratio.new(21, 20),
|
40
|
+
Ratio.new( 7, 6),
|
41
|
+
Ratio.new( 3, 2),
|
42
|
+
Ratio.new(14, 9),
|
43
|
+
Ratio.new( 2, 1)
|
44
|
+
])
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module ShlispTools
|
2
|
+
module Shnth
|
3
|
+
Light_1 = 1
|
4
|
+
Light_2 = Light_1 * 4
|
5
|
+
Light_3 = Light_2 * 4
|
6
|
+
Light_4 = Light_3 * 4
|
7
|
+
Light_5 = Light_4 * 4
|
8
|
+
Light_6 = Light_5 * 4
|
9
|
+
Light_7 = Light_6 * 4
|
10
|
+
Light_8 = Light_7 * 4
|
11
|
+
|
12
|
+
Situation_1 = "(jump (tar 1)) (lights #{Light_1})"
|
13
|
+
Situation_2 = "(jump (tar 1)) (lights #{Light_2})"
|
14
|
+
Situation_3 = "(jump (tar 1)) (lights #{Light_3})"
|
15
|
+
Situation_4 = "(jump (tar 1)) (lights #{Light_4})"
|
16
|
+
Situation_5 = "(jump (tar 1)) (lights #{Light_5})"
|
17
|
+
Situation_6 = "(jump (tar 1)) (lights #{Light_6})"
|
18
|
+
Situation_7 = "(jump (tar 1)) (lights #{Light_7})"
|
19
|
+
Situation_8 = "(jump (tar 1)) (lights #{Light_8})"
|
20
|
+
|
21
|
+
# scale indexes by bar (A=major, a=minora), using stevek's arrangement
|
22
|
+
Bar_A = 0
|
23
|
+
Bar_B = 1
|
24
|
+
Bar_C = 2
|
25
|
+
Bar_D = 3
|
26
|
+
Bar_d = 4
|
27
|
+
Bar_c = 5
|
28
|
+
Bar_b = 6
|
29
|
+
Bar_a = 7
|
30
|
+
end
|
31
|
+
end
|
data/lib/shlisp_tools.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'shlisp_tools/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "shlisp_tools"
|
8
|
+
spec.version = ShlispTools::VERSION
|
9
|
+
spec.authors = ["Dave Seidel"]
|
10
|
+
spec.email = ["dave.seidel@gmail.com"]
|
11
|
+
spec.description = %q{shtool, shlerb, the Scale and Ratio classes, and the Scales and Shnth modules}
|
12
|
+
spec.summary = %q{Tools for shlisp/shnth users.}
|
13
|
+
spec.homepage = "http://gthub.com/DaveSeidel"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
spec.add_development_dependency "rspec"
|
24
|
+
end
|
metadata
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: shlisp_tools
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Dave Seidel
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-12-12 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: bundler
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '1.3'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1.3'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rake
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rspec
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
description: shtool, shlerb, the Scale and Ratio classes, and the Scales and Shnth
|
63
|
+
modules
|
64
|
+
email:
|
65
|
+
- dave.seidel@gmail.com
|
66
|
+
executables:
|
67
|
+
- shlerb
|
68
|
+
- shtool
|
69
|
+
extensions: []
|
70
|
+
extra_rdoc_files: []
|
71
|
+
files:
|
72
|
+
- .gitignore
|
73
|
+
- Gemfile
|
74
|
+
- LICENSE.txt
|
75
|
+
- README.md
|
76
|
+
- Rakefile
|
77
|
+
- bin/shlerb
|
78
|
+
- bin/shtool
|
79
|
+
- examples/hexanies.txt.erb
|
80
|
+
- examples/metaslendro.txt.erb
|
81
|
+
- lib/shlisp_tools.rb
|
82
|
+
- lib/shlisp_tools/ratio.rb
|
83
|
+
- lib/shlisp_tools/scale.rb
|
84
|
+
- lib/shlisp_tools/scales.rb
|
85
|
+
- lib/shlisp_tools/shnth.rb
|
86
|
+
- lib/shlisp_tools/version.rb
|
87
|
+
- shlisp_tools.gemspec
|
88
|
+
homepage: http://gthub.com/DaveSeidel
|
89
|
+
licenses:
|
90
|
+
- MIT
|
91
|
+
post_install_message:
|
92
|
+
rdoc_options: []
|
93
|
+
require_paths:
|
94
|
+
- lib
|
95
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
96
|
+
none: false
|
97
|
+
requirements:
|
98
|
+
- - ! '>='
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
version: '0'
|
101
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
102
|
+
none: false
|
103
|
+
requirements:
|
104
|
+
- - ! '>='
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
version: '0'
|
107
|
+
requirements: []
|
108
|
+
rubyforge_project:
|
109
|
+
rubygems_version: 1.8.23
|
110
|
+
signing_key:
|
111
|
+
specification_version: 3
|
112
|
+
summary: Tools for shlisp/shnth users.
|
113
|
+
test_files: []
|