ramekin 0.0.9 → 0.0.11
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.
- checksums.yaml +4 -4
- data/lib/ramekin/cli.rb +1 -0
- data/lib/ramekin/errors.rb +3 -1
- data/lib/ramekin/legato.rb +2 -2
- data/lib/ramekin/loop_allocator.rb +47 -0
- data/lib/ramekin/meta.rb +37 -3
- data/lib/ramekin/note_aggregator.rb +12 -6
- data/lib/ramekin/renderer.rb +23 -9
- data/lib/ramekin/tokenizer.rb +3 -4
- data/lib/ramekin/util.rb +13 -0
- data/lib/ramekin.rb +1 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f9fce3c7ec61c39d7597621bf02fbd71788df731ee7a98cb89018549275eb44e
|
4
|
+
data.tar.gz: 0c123977b81c24d92f4f6b3514973ca4713aedf4c8292aa30d126f6b20d541ea
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0d4484cc76d708e7b1d36929e2a4b95efe19b34ad5882f51e71d526bd08d1c500725de40054b17e5401922fd388854a2866fca0a2210a15589bdbd5e46bc85b4
|
7
|
+
data.tar.gz: cd54afeb74289aaf055344b45aca6b75679b494db546308c0d86d05866c0a4e4cc855921232f7c6507ac8cc6a2b8e6656247ba6ea579806c1589786470ce2f31
|
data/lib/ramekin/cli.rb
CHANGED
data/lib/ramekin/errors.rb
CHANGED
@@ -15,7 +15,7 @@ module Ramekin
|
|
15
15
|
def self.error!(e, nesting: 0)
|
16
16
|
all << e
|
17
17
|
|
18
|
-
if ENV['RAMEKIN_DEBUG'] == '1'
|
18
|
+
if ENV['RAMEKIN_DEBUG'] == '1' && ENV['DISABLE_PRY'] != 'true'
|
19
19
|
if nesting >= 0
|
20
20
|
Pry.config.hooks.add_hook(:before_session, :ramekin) do |output, binding, pry|
|
21
21
|
Pry.config.hooks.delete_hook(:before_session, :ramekin)
|
@@ -25,6 +25,8 @@ module Ramekin
|
|
25
25
|
|
26
26
|
binding.pry
|
27
27
|
end
|
28
|
+
|
29
|
+
nil
|
28
30
|
end
|
29
31
|
|
30
32
|
def initialize(start, fin, message)
|
data/lib/ramekin/legato.rb
CHANGED
@@ -32,10 +32,10 @@ module Ramekin
|
|
32
32
|
@note.ticks / 2
|
33
33
|
end
|
34
34
|
|
35
|
-
def to_amk(current_octave=nil)
|
35
|
+
def to_amk(current_octave=nil, divisor=1)
|
36
36
|
post_ticks = @note.ticks - ticks
|
37
37
|
post_len = KNOWN_LENGTHS.fetch(post_ticks) { "=#{post_ticks}" }
|
38
|
-
"#{octave_amk(current_octave)}#{note_name}#{length_amk}$f4$01^#{post_len}"
|
38
|
+
"#{octave_amk(current_octave)}#{note_name}#{length_amk(divisor)}$f4$01^#{post_len}"
|
39
39
|
end
|
40
40
|
|
41
41
|
def inspect
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Ramekin
|
2
|
+
class LoopAllocator < Processor
|
3
|
+
def call(&b)
|
4
|
+
tokens = @stream.to_a
|
5
|
+
|
6
|
+
loop_defs = tokens.select do |tok|
|
7
|
+
Token === tok && tok.type == :loop && !tok.value.empty?
|
8
|
+
end
|
9
|
+
|
10
|
+
index = 0
|
11
|
+
indices = {}
|
12
|
+
used = Set.new
|
13
|
+
|
14
|
+
numbered, named = loop_defs.partition do |tok|
|
15
|
+
/\A\d+\z/.match?(tok.value)
|
16
|
+
end
|
17
|
+
|
18
|
+
numbered.each do |tok|
|
19
|
+
num = indices[tok.value] = tok.value.to_i
|
20
|
+
tok.meta[:number] = num
|
21
|
+
used << num
|
22
|
+
end
|
23
|
+
|
24
|
+
named.each do |tok|
|
25
|
+
if indices.key?(tok.value)
|
26
|
+
error! "multiple definitions of (#{tok.value})", el: tok
|
27
|
+
next
|
28
|
+
end
|
29
|
+
|
30
|
+
index += 1
|
31
|
+
index += 1 while used.include?(index)
|
32
|
+
indices[tok.value] = index
|
33
|
+
tok.meta[:number] = index
|
34
|
+
end
|
35
|
+
|
36
|
+
tokens.each do |token|
|
37
|
+
if Token === token && token.type == :loop_call
|
38
|
+
token.meta[:number] = indices.fetch(token.value) do
|
39
|
+
error! "no such loop", el: token
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
yield token
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/lib/ramekin/meta.rb
CHANGED
@@ -48,6 +48,34 @@ module Ramekin
|
|
48
48
|
)
|
49
49
|
end
|
50
50
|
|
51
|
+
def t_value
|
52
|
+
t_with_divisor[0]
|
53
|
+
end
|
54
|
+
|
55
|
+
def divisor
|
56
|
+
t_with_divisor[1]
|
57
|
+
end
|
58
|
+
|
59
|
+
def t_with_divisor
|
60
|
+
return [50, 1] if @tempo.nil?
|
61
|
+
|
62
|
+
@t_with_divisor ||= begin
|
63
|
+
t = case @tempo.type
|
64
|
+
when :t then @tempo.value
|
65
|
+
when :bpm then (@tempo.value.to_f * 8192 / 20025.0)
|
66
|
+
end
|
67
|
+
|
68
|
+
t = t.to_f
|
69
|
+
divisor = 1
|
70
|
+
while t > 60
|
71
|
+
t /= 2
|
72
|
+
divisor *= 2
|
73
|
+
end
|
74
|
+
|
75
|
+
[t.round, divisor]
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
51
79
|
def parse
|
52
80
|
loop do
|
53
81
|
break if @elements.empty?
|
@@ -58,7 +86,7 @@ module Ramekin
|
|
58
86
|
when :amk then @amk = @current
|
59
87
|
when :option then @options[@current.value] = true
|
60
88
|
when :w then @volume = @current
|
61
|
-
when :t, :bpm then @tempo = @current
|
89
|
+
when :t, :bpm then @tempo = @current; @t_with_divisor = nil
|
62
90
|
else
|
63
91
|
error! 'invalid token in header'
|
64
92
|
end
|
@@ -282,7 +310,7 @@ module Ramekin
|
|
282
310
|
|
283
311
|
def ext_gain
|
284
312
|
gain = @extensions.select { |e| e.type == :gain }.last
|
285
|
-
gain && gain.value
|
313
|
+
gain && to_hex(gain.value.to_i(16))
|
286
314
|
end
|
287
315
|
|
288
316
|
def gain
|
@@ -299,7 +327,13 @@ module Ramekin
|
|
299
327
|
adsr1 = ((7 - d)*16 | 0x80) + (15 - a)
|
300
328
|
adsr2 = (s*32 + (31-r))
|
301
329
|
|
302
|
-
[adsr1
|
330
|
+
[to_hex(adsr1), to_hex(adsr2), g, t1, t2]
|
331
|
+
end
|
332
|
+
|
333
|
+
def to_hex(x)
|
334
|
+
return x if x.is_a?(String)
|
335
|
+
|
336
|
+
sprintf("%02x", x)
|
303
337
|
end
|
304
338
|
|
305
339
|
def to_amk
|
@@ -57,10 +57,16 @@ module Ramekin
|
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
60
|
-
def length_amk
|
60
|
+
def length_amk(div)
|
61
|
+
if ticks % div != 0
|
62
|
+
divisible = div == 2 ? 'even' : "divisible by #{div}"
|
63
|
+
error!("too fast! tick count must be #{divisible} at this tempo", el: self)
|
64
|
+
end
|
65
|
+
|
66
|
+
t = ticks / div
|
61
67
|
# we use l16
|
62
|
-
return '' if
|
63
|
-
KNOWN_LENGTHS.fetch(
|
68
|
+
return '' if t == 12
|
69
|
+
KNOWN_LENGTHS.fetch(t) { "=#{t}" }
|
64
70
|
end
|
65
71
|
|
66
72
|
def octave_amk(current_octave=nil)
|
@@ -80,8 +86,8 @@ module Ramekin
|
|
80
86
|
end
|
81
87
|
end
|
82
88
|
|
83
|
-
def to_amk(current_octave=nil)
|
84
|
-
return "#{octave_amk(current_octave)}#{note_name}#{length_amk}"
|
89
|
+
def to_amk(current_octave=nil, divisor=1)
|
90
|
+
return "#{octave_amk(current_octave)}#{note_name}#{length_amk(divisor)}"
|
85
91
|
end
|
86
92
|
|
87
93
|
def repr
|
@@ -94,7 +100,7 @@ module Ramekin
|
|
94
100
|
|
95
101
|
def ticks
|
96
102
|
if @extensions.empty? && default_length.nil?
|
97
|
-
|
103
|
+
return 192 / 16
|
98
104
|
end
|
99
105
|
|
100
106
|
exts = @extensions
|
data/lib/ramekin/renderer.rb
CHANGED
@@ -58,7 +58,7 @@ module Ramekin
|
|
58
58
|
|
59
59
|
render_preamble(&b)
|
60
60
|
|
61
|
-
@track.channels.each { |c| render_channel(c, &b) }
|
61
|
+
@track.channels.compact.each { |c| render_channel(c, &b) }
|
62
62
|
end
|
63
63
|
|
64
64
|
def render_preamble(&b)
|
@@ -101,7 +101,7 @@ module Ramekin
|
|
101
101
|
yield "}\n\n"
|
102
102
|
end
|
103
103
|
|
104
|
-
yield "t#{
|
104
|
+
yield "t#{m.t_value} ; main tempo (0-60)\n" if m.tempo
|
105
105
|
yield "w#{m.volume.value} ; main volume (0-255)\n" if m.volume
|
106
106
|
yield "l16\n\n"
|
107
107
|
|
@@ -143,12 +143,14 @@ module Ramekin
|
|
143
143
|
if (old_tick-1) / 192 != (@tick-1) / 192
|
144
144
|
yield "\n"
|
145
145
|
end
|
146
|
-
|
146
|
+
divisor = @track.meta.divisor
|
147
|
+
|
148
|
+
yield el.to_amk(@octave, @track.meta.divisor)
|
147
149
|
@octave = el.octave unless el.rest?
|
148
150
|
when MacroDefinition
|
149
151
|
# pass
|
150
152
|
when LegatoStart, LegatoLastNote
|
151
|
-
yield el.to_amk
|
153
|
+
yield el.to_amk(@octave, @track.meta.divisor)
|
152
154
|
when Instrument
|
153
155
|
yield "@#{@instrument_index[el.name.value]}"
|
154
156
|
when Token
|
@@ -188,13 +190,25 @@ module Ramekin
|
|
188
190
|
end
|
189
191
|
when :v
|
190
192
|
vol, time = token.values.compact.map(&:to_i)
|
191
|
-
|
193
|
+
|
194
|
+
unless Token === peek && [:v, :relv].include?(peek.type)
|
195
|
+
yield velocity_command(vol, time)
|
196
|
+
end
|
197
|
+
|
192
198
|
@volume = vol
|
193
199
|
when :relv
|
194
200
|
relvol, duration = token.values
|
195
|
-
|
201
|
+
|
202
|
+
unless Token === peek && [:v, :relv].include?(peek.type)
|
203
|
+
yield velocity_command(@volume + relvol.to_i, duration)
|
204
|
+
end
|
196
205
|
when :q
|
197
|
-
|
206
|
+
token.value =~ /(\d),?(\h)?/
|
207
|
+
qval = $1
|
208
|
+
gain = $2 || 'F'
|
209
|
+
yield "q#{qval}#{gain}"
|
210
|
+
when :w
|
211
|
+
yield "w#{token.value}"
|
198
212
|
when :adsr
|
199
213
|
vals = token.value.split(',').map { |x| x.to_i(16) }
|
200
214
|
error! 'invalid #adsr, expected 4 arguments' unless vals.size == 4
|
@@ -229,14 +243,14 @@ module Ramekin
|
|
229
243
|
yield " [[ "
|
230
244
|
when :loop
|
231
245
|
if token.value
|
232
|
-
yield " (#{token.
|
246
|
+
yield " (#{token.meta[:number]})[ "
|
233
247
|
else
|
234
248
|
yield " [ "
|
235
249
|
end
|
236
250
|
when :loop_end
|
237
251
|
yield " ]#{token.value} "
|
238
252
|
when :loop_call
|
239
|
-
yield " (#{token.
|
253
|
+
yield " (#{token.meta[:number]})#{token.values[1]} "
|
240
254
|
when :star
|
241
255
|
yield "*#{token.value}"
|
242
256
|
when :superloop_end
|
data/lib/ramekin/tokenizer.rb
CHANGED
@@ -228,7 +228,6 @@ module Ramekin
|
|
228
228
|
return [:instrument, m(1)] if match /@(\w+)/
|
229
229
|
return [:hex, m(1)] if match /[$](\h\h)/
|
230
230
|
return [:t, m(1)] if match /t(\d+)/
|
231
|
-
return [:q, m(1)] if match /q(\d\h?)/
|
232
231
|
|
233
232
|
return note(:note, m) if match /[abcdefg][+-]?/
|
234
233
|
return note(:r) if match /r/
|
@@ -244,9 +243,9 @@ module Ramekin
|
|
244
243
|
return [:superloop_end, m(1)] if match /\]\](\d*)/
|
245
244
|
|
246
245
|
return [:remote_def, m(1)] if match /[(]!(\d+)[)]\[/
|
247
|
-
return [:loop, m(1)] if match /(?:[(](\
|
246
|
+
return [:loop, m(1)] if match /(?:[(]([\w-]+)[)])?\[/
|
248
247
|
return [:loop_end, m(1)] if match /\](\d*)/
|
249
|
-
return [:loop_call, m(1), m(2)] if match /[(](\
|
248
|
+
return [:loop_call, m(1), m(2)] if match /[(]([\w-]+)[)](\d+)?/
|
250
249
|
|
251
250
|
# this needs a reparse
|
252
251
|
return remote(:remote_call, m(1)) if match /[(]!(\d*)/
|
@@ -258,7 +257,7 @@ module Ramekin
|
|
258
257
|
return [:w, m(1)] if match /w(\d+)/
|
259
258
|
return [:l, m(1)] if match /l(\d+)/
|
260
259
|
return [:amp] if match /[&]/
|
261
|
-
return [:q, m(1)] if match /q(\h
|
260
|
+
return [:q, m(1)] if match /q(\d(?:,\h)?)/
|
262
261
|
return [:n, m(1)] if match /n(\h\h?)/
|
263
262
|
|
264
263
|
error! "unknown token near: #{@scanner.peek(10)}", el: @last_token
|
data/lib/ramekin/util.rb
CHANGED
@@ -44,11 +44,24 @@ module Ramekin
|
|
44
44
|
env = {}
|
45
45
|
kw.each { |k, v| env[k.to_s] = v }
|
46
46
|
|
47
|
+
$stderr.puts "run: #{a.map(&method(:shell_inspect)).join(' ')}"
|
47
48
|
system(env, *a.map(&:to_s))
|
48
49
|
rescue Interrupt
|
49
50
|
# allow interrupt out of the subprocess but capture it for ramekin itself
|
50
51
|
end
|
51
52
|
|
53
|
+
# for diagnostic purposes only, not a real escape system.
|
54
|
+
# our shellouts don't need escapes since they are not actually
|
55
|
+
# interpreted by a shell.
|
56
|
+
def shell_inspect(s)
|
57
|
+
s = s.to_s
|
58
|
+
if s =~ /[\s'"&*]/
|
59
|
+
s.inspect
|
60
|
+
else
|
61
|
+
s
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
52
65
|
def executable?(path)
|
53
66
|
stat = File.stat(path)
|
54
67
|
stat.file? && stat.executable?
|
data/lib/ramekin.rb
CHANGED
@@ -11,6 +11,7 @@ require_relative 'ramekin/processor'
|
|
11
11
|
require_relative 'ramekin/macros'
|
12
12
|
require_relative 'ramekin/note_aggregator'
|
13
13
|
require_relative 'ramekin/legato'
|
14
|
+
require_relative 'ramekin/loop_allocator'
|
14
15
|
require_relative 'ramekin/meta'
|
15
16
|
require_relative 'ramekin/channel_separator'
|
16
17
|
require_relative 'ramekin/volume'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ramekin
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.11
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- jneen
|
8
8
|
autorequire:
|
9
9
|
bindir: gembin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-02-
|
11
|
+
date: 2025-02-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: strscan
|
@@ -85,6 +85,7 @@ files:
|
|
85
85
|
- lib/ramekin/element.rb
|
86
86
|
- lib/ramekin/errors.rb
|
87
87
|
- lib/ramekin/legato.rb
|
88
|
+
- lib/ramekin/loop_allocator.rb
|
88
89
|
- lib/ramekin/macros.rb
|
89
90
|
- lib/ramekin/meta.rb
|
90
91
|
- lib/ramekin/note_aggregator.rb
|