shlisp_tools 0.0.1 → 0.0.2
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/README.md +13 -1
- data/bin/shlerb +6 -6
- data/bin/shtool +9 -9
- data/examples/hexanies.txt.erb +1 -1
- data/examples/metaslendro.txt.erb +2 -2
- data/lib/shlisp_tools/ratio.rb +42 -28
- data/lib/shlisp_tools/scale.rb +57 -20
- data/lib/shlisp_tools/scales.rb +7 -0
- data/lib/shlisp_tools/shnth.rb +22 -2
- data/lib/shlisp_tools/version.rb +1 -1
- metadata +2 -2
data/README.md
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# ShlispTools
|
2
2
|
|
3
|
-
|
3
|
+
[](http://badge.fury.io/rb/shlisp_tools)
|
4
|
+
|
5
|
+
Tools for shlisp/shnth developers. If you don't recognize both words starting with "sh", this is probably not for you.
|
4
6
|
|
5
7
|
Executables:
|
6
8
|
* shlerb (a templating and uploading tool for txts; an ERB wrapper for shlisp)
|
@@ -110,6 +112,16 @@ You can also define your own scales and add a scaling factor to bring them into
|
|
110
112
|
|
111
113
|
%>
|
112
114
|
|
115
|
+
## Caveats
|
116
|
+
|
117
|
+
* Ratio, Scale, and the Scales collection all assume "arab" mode.
|
118
|
+
|
119
|
+
## TODO
|
120
|
+
|
121
|
+
* write tests
|
122
|
+
* write more complete documentation
|
123
|
+
* allow Ratio and Scale classes to work in "dirac" mode as well as "arab" mode
|
124
|
+
|
113
125
|
## Contributing
|
114
126
|
|
115
127
|
1. Fork it
|
data/bin/shlerb
CHANGED
@@ -1,36 +1,36 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require 'erb'
|
4
|
-
|
5
4
|
require 'shlisp_tools'
|
6
5
|
|
7
|
-
|
6
|
+
#:nodoc: all
|
8
7
|
Scales = ShlispTools::Scales
|
9
8
|
Shnth = ShlispTools::Shnth
|
10
9
|
|
11
|
-
def error(s)
|
10
|
+
def error(s) #:nodoc:
|
12
11
|
puts s
|
13
12
|
exit 1
|
14
13
|
end
|
15
14
|
|
16
|
-
class Shlerb
|
17
|
-
|
15
|
+
class Shlerb #:nodoc: all
|
18
16
|
TEMP_FILE = "_shlerb_temp"
|
19
17
|
|
20
18
|
def self.perform(infile)
|
21
19
|
template_file = File.open(infile, 'r').read
|
22
20
|
out = nil
|
23
21
|
|
22
|
+
puts "Generating shlisp..."
|
24
23
|
begin
|
25
24
|
out = herb(template_file)
|
26
25
|
rescue Exception => e
|
27
|
-
# do again and show
|
26
|
+
# do again and show verbose output
|
28
27
|
$VERBOSE = true
|
29
28
|
puts herb(template_file)
|
30
29
|
exit 1
|
31
30
|
end
|
32
31
|
|
33
32
|
if out
|
33
|
+
puts "Compiling generated shlisp (#{TEMP_FILE}) and sending to shnth..."
|
34
34
|
File.open(TEMP_FILE, 'w+') { |f| f.write(out) }
|
35
35
|
system("shlisp #{TEMP_FILE}")
|
36
36
|
end
|
data/bin/shtool
CHANGED
@@ -4,7 +4,7 @@
|
|
4
4
|
# ops
|
5
5
|
#------------------------------------------------------------------------------
|
6
6
|
|
7
|
-
class OpResult
|
7
|
+
class OpResult #:nodoc: all
|
8
8
|
attr_reader :args, :result
|
9
9
|
|
10
10
|
def initialize(args=nil, result=nil)
|
@@ -18,7 +18,7 @@ class OpResult
|
|
18
18
|
end
|
19
19
|
|
20
20
|
# base class for operations
|
21
|
-
class Op
|
21
|
+
class Op #:nodoc: all
|
22
22
|
def self.name
|
23
23
|
""
|
24
24
|
end
|
@@ -49,7 +49,7 @@ end
|
|
49
49
|
|
50
50
|
# operations
|
51
51
|
|
52
|
-
class OpSr < Op
|
52
|
+
class OpSr < Op #:nodoc: all
|
53
53
|
CLOCK = 72000000.0
|
54
54
|
|
55
55
|
def self.name
|
@@ -82,7 +82,7 @@ class OpSr < Op
|
|
82
82
|
end
|
83
83
|
end
|
84
84
|
|
85
|
-
class OpRatMul < Op
|
85
|
+
class OpRatMul < Op #:nodoc: all
|
86
86
|
def self.name
|
87
87
|
"mul"
|
88
88
|
end
|
@@ -118,7 +118,7 @@ class OpRatMul < Op
|
|
118
118
|
end
|
119
119
|
end
|
120
120
|
|
121
|
-
class OpRange < Op
|
121
|
+
class OpRange < Op #:nodoc: all
|
122
122
|
Min = -128
|
123
123
|
Max = 128
|
124
124
|
|
@@ -154,7 +154,7 @@ class OpRange < Op
|
|
154
154
|
end
|
155
155
|
end
|
156
156
|
|
157
|
-
class OpReduce < Op
|
157
|
+
class OpReduce < Op #:nodoc: all
|
158
158
|
def self.name
|
159
159
|
"reduce"
|
160
160
|
end
|
@@ -192,20 +192,20 @@ class OpReduce < Op
|
|
192
192
|
end
|
193
193
|
|
194
194
|
# known operations
|
195
|
-
Ops = [ OpSr, OpRatMul, OpRange, OpReduce ]
|
195
|
+
Ops = [ OpSr, OpRatMul, OpRange, OpReduce ] #:nodoc:
|
196
196
|
|
197
197
|
#------------------------------------------------------------------------------
|
198
198
|
# mainline code
|
199
199
|
#------------------------------------------------------------------------------
|
200
200
|
|
201
|
-
def usage
|
201
|
+
def usage #:nodoc:
|
202
202
|
puts "usage: 'shtool OP [args ...]'"
|
203
203
|
puts "where OP is one of: #{Ops.collect{ |op| op.name}.join(" ") }"
|
204
204
|
puts "or try 'shtool help'"
|
205
205
|
exit 1
|
206
206
|
end
|
207
207
|
|
208
|
-
def main(argv)
|
208
|
+
def main(argv) #:nodoc:
|
209
209
|
if argv.length < 1
|
210
210
|
usage
|
211
211
|
else
|
data/examples/hexanies.txt.erb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
Slew_add = 5
|
4
4
|
Modo_mul = 2
|
5
5
|
%>
|
6
|
-
<% s1 = Scales::MetaSlendro_1.
|
6
|
+
<% s1 = Scales::MetaSlendro_1.mul(120) %>
|
7
7
|
{
|
8
8
|
<%= Shnth::Situation_1 %>
|
9
9
|
|
@@ -32,7 +32,7 @@
|
|
32
32
|
|
33
33
|
)
|
34
34
|
}
|
35
|
-
<% s2 = Scales::MetaSlendro_2.
|
35
|
+
<% s2 = Scales::MetaSlendro_2.mul(120) %>
|
36
36
|
{
|
37
37
|
<%= Shnth::Situation_2 %>
|
38
38
|
|
data/lib/shlisp_tools/ratio.rb
CHANGED
@@ -1,81 +1,95 @@
|
|
1
1
|
module ShlispTools
|
2
|
+
|
3
|
+
# A Shlisp-oriented representation of a pitch in just/rational intonation.
|
4
|
+
# Numerators are "numes" and denoninators are "denos" as is customary for
|
5
|
+
# Shlisp. All terms 0 < n < 256 ("arab" mode in Shlisp).
|
2
6
|
class Ratio
|
3
7
|
include Enumerable
|
4
8
|
|
5
|
-
|
9
|
+
# numerator
|
10
|
+
attr_reader :nume
|
11
|
+
# denominator
|
12
|
+
attr_reader :deno
|
13
|
+
# rational form
|
14
|
+
attr_reader :rat
|
6
15
|
|
7
|
-
def initialize(nume, deno,
|
16
|
+
def initialize(nume, deno, _mul=nil)
|
8
17
|
@nume = nume
|
9
18
|
@deno = deno
|
10
19
|
_set_rat
|
11
|
-
|
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
|
20
|
+
mul(_mul)
|
31
21
|
end
|
32
22
|
|
23
|
+
# Get the nume(rator).
|
33
24
|
def n
|
34
25
|
@nume
|
35
26
|
end
|
36
27
|
|
28
|
+
# Set the nume(rator).
|
37
29
|
def n=(nume)
|
38
30
|
@nume = nume
|
39
31
|
_set_rat
|
32
|
+
n
|
40
33
|
end
|
41
34
|
|
35
|
+
# Get the deno(minator).
|
42
36
|
def d
|
43
37
|
@deno
|
44
38
|
end
|
45
39
|
|
40
|
+
# Set the deno(minator).
|
46
41
|
def d=(deno)
|
47
42
|
@deno = deno
|
48
43
|
_set_rat
|
44
|
+
d
|
49
45
|
end
|
50
46
|
|
51
|
-
|
52
|
-
|
47
|
+
# Multiply both nume and deno by same factor for Shnth amplitude scaling.
|
48
|
+
def mul(factor)
|
49
|
+
if factor
|
50
|
+
factor = factor.abs
|
51
|
+
@nume = (@nume * factor) % LIMIT
|
52
|
+
@deno = (@deno * factor) % LIMIT
|
53
|
+
end
|
54
|
+
self
|
53
55
|
end
|
54
56
|
|
55
|
-
|
57
|
+
def scale(factor) #:nodoc:
|
58
|
+
mul(factor)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Return to the canonical (reduced) value.
|
62
|
+
def reset!
|
56
63
|
@nume = @rat.numerator
|
57
64
|
@deno = @rat.denominator
|
58
65
|
end
|
59
66
|
|
67
|
+
# String representation
|
60
68
|
def to_s
|
61
69
|
"#{@nume}/#{@deno}"
|
62
70
|
end
|
63
71
|
|
72
|
+
# Rational representation
|
64
73
|
def to_r
|
65
74
|
@rat
|
66
75
|
end
|
67
76
|
|
68
|
-
|
77
|
+
# Iterator
|
78
|
+
def each #:nodoc:
|
69
79
|
yield @rat
|
70
80
|
end
|
71
81
|
|
72
|
-
|
82
|
+
# Comparator, for sorting
|
83
|
+
def <=>(other) #:nodoc:
|
73
84
|
@rat <=> other.rat
|
74
85
|
end
|
75
86
|
|
76
87
|
private
|
77
|
-
|
88
|
+
LIMIT = 256 #:nodoc:
|
89
|
+
|
90
|
+
def _set_rat #:nodoc:
|
78
91
|
@rat = Rational(@nume, @deno)
|
79
92
|
end
|
80
93
|
end
|
94
|
+
|
81
95
|
end
|
data/lib/shlisp_tools/scale.rb
CHANGED
@@ -1,9 +1,15 @@
|
|
1
1
|
module ShlispTools
|
2
|
+
|
3
|
+
# A scale is a series of Ratio instances, always maintained in canonical
|
4
|
+
# (reduced) form and ascending order, but available with amplitude scaling
|
5
|
+
# for use in a Shlisp/Shnth context.
|
2
6
|
class Scale
|
3
7
|
include Enumerable
|
4
8
|
|
9
|
+
# The default separator (' ') between scale degrees when scale is printed.
|
5
10
|
DEF_SEP = ' '
|
6
11
|
|
12
|
+
# Arg: either nothing, or an array of Ratios
|
7
13
|
def initialize(degrees=nil)
|
8
14
|
@degrees = []
|
9
15
|
if degrees && !degrees.empty?
|
@@ -12,72 +18,103 @@ module ShlispTools
|
|
12
18
|
end
|
13
19
|
end
|
14
20
|
|
21
|
+
# Add a new scale degree (Ratio).
|
15
22
|
def add(degree)
|
16
23
|
@degrees << degree
|
17
24
|
_sort
|
25
|
+
self
|
18
26
|
end
|
19
27
|
|
20
|
-
|
21
|
-
|
28
|
+
# Add a new scal degree (Ratio) using string/array notation; i.e., myScale << Ratio.new(5,4)/
|
29
|
+
def <<(degree)
|
30
|
+
add(degree)
|
31
|
+
self
|
22
32
|
end
|
23
33
|
|
24
|
-
|
25
|
-
|
26
|
-
|
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
|
34
|
+
# Remove the scale degree at the specified position (0-based).
|
35
|
+
def remove(idx)
|
36
|
+
@degrees.delete_at(idx) rescue nil
|
35
37
|
self
|
36
38
|
end
|
37
39
|
|
40
|
+
# Return the scale degree at a specified postion (0-based).
|
38
41
|
def [](idx)
|
39
42
|
@degrees[idx] rescue nil
|
40
43
|
end
|
41
44
|
|
45
|
+
# Return the number of degrees (notes) in the scale.
|
42
46
|
def length
|
43
47
|
@degrees.length
|
44
48
|
end
|
45
49
|
|
50
|
+
# Return true if scale is empty, false otherwise.
|
46
51
|
def empty?
|
47
52
|
@degrees.empty?
|
48
53
|
end
|
49
54
|
|
50
|
-
|
51
|
-
|
55
|
+
# Apply a multiplicative factor to every ratio for Shnth amplitude scaling.
|
56
|
+
# For example, myScale.scale(100) transforms 1/1 to 100/100. Other notes are brought into
|
57
|
+
# as close a range as possible while keeping all terms in the 1..255 range.
|
58
|
+
def mul(factor)
|
59
|
+
unless empty?
|
60
|
+
@degrees.each_with_index do |note,i|
|
61
|
+
if i == 0
|
62
|
+
note.mul(factor)
|
63
|
+
else
|
64
|
+
tmp = ((factor > note.deno) ? factor : factor*2)
|
65
|
+
note.mul((tmp / note.deno).to_i)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
self
|
52
70
|
end
|
53
71
|
|
54
|
-
def
|
55
|
-
|
72
|
+
def scale(factor) #:nodoc:
|
73
|
+
mul(factor)
|
56
74
|
end
|
57
75
|
|
76
|
+
# Print the scale (multipied).
|
58
77
|
def to_s
|
59
|
-
|
78
|
+
multiplied
|
60
79
|
end
|
61
80
|
|
62
|
-
|
81
|
+
# Print out the scale (multiplied).
|
82
|
+
def multiplied(sep=DEF_SEP)
|
63
83
|
@degrees.inject([]) { |out,d| out << d.to_s; out }.join(sep)
|
64
84
|
end
|
65
85
|
|
66
|
-
def
|
86
|
+
def scaled(sep=DEF_SEP) #:nodoc:
|
87
|
+
multiplied(sep)
|
88
|
+
end
|
89
|
+
|
90
|
+
# Print out the scale in canonical form (reduced rations).
|
91
|
+
def canonical(sep=DEF_SEP)
|
67
92
|
@degrees.inject([]) { |out,d| out << d.to_r.to_s; out }.join(sep)
|
68
93
|
end
|
69
94
|
|
95
|
+
def reduced(sep=DEF_SEP) #:nodoc:
|
96
|
+
canonical(sep)
|
97
|
+
end
|
98
|
+
|
99
|
+
# Print out all the nume(rator)s, multiplied.
|
70
100
|
def numes(sep=DEF_SEP)
|
71
101
|
@degrees.inject([]) { |out,d| out << d.n; out }.join(sep)
|
72
102
|
end
|
73
103
|
|
104
|
+
# Print out all the deno(minators), multiplied.
|
74
105
|
def denos(sep=DEF_SEP)
|
75
106
|
@degrees.inject([]) { |out,d| out << d.d; out }.join(sep)
|
76
107
|
end
|
77
108
|
|
109
|
+
# iterator
|
110
|
+
def each(&block) #:nodoc
|
111
|
+
@degrees.each(&block)
|
112
|
+
end
|
113
|
+
|
78
114
|
private
|
79
115
|
def _sort
|
80
116
|
@degrees.sort!
|
81
117
|
end
|
82
118
|
end
|
119
|
+
|
83
120
|
end
|
data/lib/shlisp_tools/scales.rb
CHANGED
@@ -1,10 +1,13 @@
|
|
1
1
|
require 'shlisp_tools/scale'
|
2
2
|
|
3
3
|
module ShlispTools
|
4
|
+
|
5
|
+
# Predefined scales.
|
4
6
|
module Scales
|
5
7
|
|
6
8
|
# 1-3-5-7 hexany, utonal stellated
|
7
9
|
# second degree (49/48) and 2/1 removed to fit eight buttons
|
10
|
+
# 1/1 25/24 7/6 5/4 35/24 3/2 5/3 7/4
|
8
11
|
Hexany1357 = Scale.new([
|
9
12
|
Ratio.new( 1, 1),
|
10
13
|
Ratio.new(25, 24),
|
@@ -16,6 +19,7 @@ module ShlispTools
|
|
16
19
|
Ratio.new( 7, 4)
|
17
20
|
])
|
18
21
|
|
22
|
+
# 1/1 37/32 21/16 49/32 7/4 2/1
|
19
23
|
MetaSlendro_1 = Scale.new([
|
20
24
|
Ratio.new( 1, 1),
|
21
25
|
Ratio.new(37, 32),
|
@@ -25,6 +29,7 @@ module ShlispTools
|
|
25
29
|
Ratio.new( 2, 1)
|
26
30
|
])
|
27
31
|
|
32
|
+
# 1/1 9/8 151/128 3/2 25/16 2/1
|
28
33
|
MetaSlendro_2 = Scale.new([
|
29
34
|
Ratio.new( 1, 1),
|
30
35
|
Ratio.new( 9, 8),
|
@@ -34,6 +39,7 @@ module ShlispTools
|
|
34
39
|
Ratio.new( 2, 1)
|
35
40
|
])
|
36
41
|
|
42
|
+
# 1/1 21/20 7/6 3/2 14/9 2/1
|
37
43
|
CentaurPelog = Scale.new([
|
38
44
|
Ratio.new( 1, 1),
|
39
45
|
Ratio.new(21, 20),
|
@@ -44,4 +50,5 @@ module ShlispTools
|
|
44
50
|
])
|
45
51
|
|
46
52
|
end
|
53
|
+
|
47
54
|
end
|
data/lib/shlisp_tools/shnth.rb
CHANGED
@@ -1,5 +1,24 @@
|
|
1
1
|
module ShlispTools
|
2
|
+
|
3
|
+
=begin
|
4
|
+
Macros and constants for use with the shlerb tool.
|
5
|
+
|
6
|
+
*Light_\**: simple light values, 1-8 across
|
7
|
+
|
8
|
+
*Situation_\**: macros representing stevek's idiom for switching through situations using the tar button, using the lights from left to right
|
9
|
+
to show which situation is running:
|
10
|
+
- <tt>\<%= Situation_1 %></tt> emits <tt>(jump (tar 1)) (lights 1)</tt>
|
11
|
+
- <tt>\<%= Situation_2 %></tt> emits <tt>(jump (tar 1)) (lights 4)</tt>
|
12
|
+
- etc.
|
13
|
+
|
14
|
+
*Bar_\**: scale indexes by bar (Uppercase=major, lowercase=minor), using stevek's arrangement:
|
15
|
+
- <tt>Bar_A = 0</tt>
|
16
|
+
- <tt>Bar_B = 1</tt>
|
17
|
+
- etc.
|
18
|
+
=end
|
19
|
+
|
2
20
|
module Shnth
|
21
|
+
|
3
22
|
Light_1 = 1
|
4
23
|
Light_2 = Light_1 * 4
|
5
24
|
Light_3 = Light_2 * 4
|
@@ -17,8 +36,7 @@ module ShlispTools
|
|
17
36
|
Situation_6 = "(jump (tar 1)) (lights #{Light_6})"
|
18
37
|
Situation_7 = "(jump (tar 1)) (lights #{Light_7})"
|
19
38
|
Situation_8 = "(jump (tar 1)) (lights #{Light_8})"
|
20
|
-
|
21
|
-
# scale indexes by bar (A=major, a=minora), using stevek's arrangement
|
39
|
+
|
22
40
|
Bar_A = 0
|
23
41
|
Bar_B = 1
|
24
42
|
Bar_C = 2
|
@@ -27,5 +45,7 @@ module ShlispTools
|
|
27
45
|
Bar_c = 5
|
28
46
|
Bar_b = 6
|
29
47
|
Bar_a = 7
|
48
|
+
|
30
49
|
end
|
50
|
+
|
31
51
|
end
|
data/lib/shlisp_tools/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: shlisp_tools
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-12-
|
12
|
+
date: 2013-12-14 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|