ramekin 0.0.7 → 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +18 -0
- data/lib/ramekin/cli.rb +6 -1
- data/lib/ramekin/errors.rb +2 -2
- data/lib/ramekin/meta.rb +18 -10
- data/lib/ramekin/renderer.rb +26 -13
- data/lib/ramekin/sample_pack.rb +4 -0
- data/lib/ramekin/spc_player.rb +5 -5
- data/lib/ramekin/tokenizer.rb +4 -3
- data/lib/ramekin/util.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 463b021dd0273151c13a7590db845acf584a2df021596dd715721964e777f6d9
|
4
|
+
data.tar.gz: 432c1eccc9c5443cc63ec828f87a319141caeb3080c847948634b7935553ec86
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fbe078d3e43b620748e3bcd91360d06e1bf2b9b804821d21a6479479fe519abb7d48643a8a95f45abfcfe512b2654b1a1f6424773282d294503799e2ee31175b
|
7
|
+
data.tar.gz: bd829fcd1272ac8279757c73963e407b90ef9257d104475aa07a5c52cf3ed16ce691d25ade84a3333fa2c243854948b92a7fcbfa90b47ee2fedad9c845b54c33
|
data/README.md
CHANGED
@@ -210,6 +210,24 @@ After the instrument declaration, you can use several commands to change the def
|
|
210
210
|
|
211
211
|
It is generally advised to stick with the default tuning. The `o5` declaration sets the *default octave* for the instrument to octave 5 (the default is 4). Whenever this instrument is selected, Ramekin will insert a switch to the specified octave.
|
212
212
|
|
213
|
+
### Echo settings
|
214
|
+
|
215
|
+
Echo settings can be set up with the `#echo/...` family of directives:
|
216
|
+
|
217
|
+
```elisp
|
218
|
+
#echo/channels:0,1,2,3
|
219
|
+
; or
|
220
|
+
#echo/channels:all
|
221
|
+
; or
|
222
|
+
#echo/channels:none
|
223
|
+
|
224
|
+
#echo/volume:20 ; range from -7f to 80, use negatives for surround
|
225
|
+
#echo/volume:20,30 ; set different values for left vs right echo
|
226
|
+
#echo/feedback:48 ; range from -7f to 80, use negatives for surround
|
227
|
+
#echo/fir:1 ; 1 or 0 to enable/disable the FIR filter
|
228
|
+
```
|
229
|
+
|
230
|
+
|
213
231
|
## Channel Commands
|
214
232
|
|
215
233
|
With your metadata all set up, it's time to add some notes!
|
data/lib/ramekin/cli.rb
CHANGED
@@ -111,6 +111,11 @@ module Ramekin
|
|
111
111
|
when '--package'
|
112
112
|
@output_package = argv.shift or usage! 'missing dirname after --package'
|
113
113
|
when '--play'
|
114
|
+
if argv.any? && argv[0] =~ /\A\d+\z/
|
115
|
+
@play_offset = argv.shift
|
116
|
+
else
|
117
|
+
@play_offset = 0
|
118
|
+
end
|
114
119
|
@play = true
|
115
120
|
when '--wav'
|
116
121
|
arg = argv.shift or usage! 'missing wav file after --render'
|
@@ -232,7 +237,7 @@ module Ramekin
|
|
232
237
|
|
233
238
|
if @play
|
234
239
|
SPCPlayer.instance.setup!
|
235
|
-
SPCPlayer.instance.play(@play_spc)
|
240
|
+
SPCPlayer.instance.play(@play_spc, @play_offset)
|
236
241
|
end
|
237
242
|
|
238
243
|
if @verbose
|
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']
|
18
|
+
if ENV['RAMEKIN_DEBUG'] == '1'
|
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)
|
@@ -35,7 +35,7 @@ module Ramekin
|
|
35
35
|
|
36
36
|
def present(orig)
|
37
37
|
out = []
|
38
|
-
out << "line #{@range.start.line}, col #{@range.start.col}:"
|
38
|
+
out << "line #{@range.start.line+1}, col #{@range.start.col+1}:"
|
39
39
|
out << " ---"
|
40
40
|
out << " #{orig[@range.pos_range]}"
|
41
41
|
out << " ---"
|
data/lib/ramekin/meta.rb
CHANGED
@@ -22,7 +22,7 @@ module Ramekin
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def echo_channel_bits
|
25
|
-
(@echo_channels ||= Set.new).map { |x| 1 << x }.inject(&:|)
|
25
|
+
(@echo_channels ||= Set.new).map { |x| 1 << x }.inject(0, &:|)
|
26
26
|
end
|
27
27
|
|
28
28
|
def echo_volumes
|
@@ -63,8 +63,6 @@ module Ramekin
|
|
63
63
|
error! 'invalid token in header'
|
64
64
|
end
|
65
65
|
end
|
66
|
-
|
67
|
-
@sample_groups << 'default' if @sample_groups.empty?
|
68
66
|
end
|
69
67
|
|
70
68
|
SURROUND_R = (-0x7f..0x80)
|
@@ -84,21 +82,25 @@ module Ramekin
|
|
84
82
|
when 'instrument'
|
85
83
|
name, path = expect_args(:instrument, :string)
|
86
84
|
extensions = []
|
87
|
-
while (el = check_arg(:adsr, :tuning, :o))
|
85
|
+
while (el = check_arg(:adsr, :tuning, :gain, :o))
|
88
86
|
extensions << el
|
89
87
|
end
|
90
88
|
|
91
89
|
return unless @current_pack
|
92
|
-
@instruments << Instrument.new(@current_pack, @
|
90
|
+
@instruments << Instrument.new(@current_pack, @current_directive, name, path, extensions)
|
93
91
|
when 'default', 'optimized' then @sample_groups << @current
|
94
92
|
|
95
93
|
# TODO: real echo syntax
|
96
94
|
when 'echo' then @echo = expect_args(*([:hex] * 8))
|
97
95
|
when 'echo/channels'
|
98
96
|
channels = @current_directive.values[1]
|
99
|
-
|
97
|
+
case channels
|
98
|
+
when 'all'
|
100
99
|
@echo_channels = Set.new(0..7)
|
101
100
|
return
|
101
|
+
when 'none'
|
102
|
+
@echo_channels = Set.new
|
103
|
+
return
|
102
104
|
end
|
103
105
|
|
104
106
|
unless channels && channels =~ /\A\d(,\d)+\z/
|
@@ -250,12 +252,12 @@ module Ramekin
|
|
250
252
|
|
251
253
|
def adsr
|
252
254
|
@adsr ||= ext_adsr || pack_adsr \
|
253
|
-
or error! "no adsr configured for #{name}"
|
255
|
+
or error! "no adsr configured for #{name.value}", el: name
|
254
256
|
end
|
255
257
|
|
256
258
|
def tuning
|
257
259
|
@tuning ||= ext_tuning || pack_tuning \
|
258
|
-
or error! "no tuning configured for #{name}"
|
260
|
+
or error! "no tuning configured for #{name.value}", el: name
|
259
261
|
end
|
260
262
|
|
261
263
|
def pack_tuning
|
@@ -284,8 +286,7 @@ module Ramekin
|
|
284
286
|
end
|
285
287
|
|
286
288
|
def gain
|
287
|
-
@gain ||= ext_gain || pack_gain
|
288
|
-
or error! "no gain configured for #{name}"
|
289
|
+
@gain ||= ext_gain || pack_gain || 0xFF
|
289
290
|
end
|
290
291
|
|
291
292
|
def hexes
|
@@ -293,6 +294,8 @@ module Ramekin
|
|
293
294
|
t1, t2 = self.tuning
|
294
295
|
g = self.gain
|
295
296
|
|
297
|
+
return [] unless a && d && s && r && t1 && t2 && g
|
298
|
+
|
296
299
|
adsr1 = ((7 - d)*16 | 0x80) + (15 - a)
|
297
300
|
adsr2 = (s*32 + (31-r))
|
298
301
|
|
@@ -300,6 +303,11 @@ module Ramekin
|
|
300
303
|
end
|
301
304
|
|
302
305
|
def to_amk
|
306
|
+
unless @pack.has?(@path.value)
|
307
|
+
error! "no sample named #{path.value.inspect} in pack #{pack.name.inspect}", el: @path
|
308
|
+
return ''
|
309
|
+
end
|
310
|
+
|
303
311
|
"#{File.basename(sample_name).inspect} #{hexes.map { |h| "$#{h}" }.join(' ')}"
|
304
312
|
end
|
305
313
|
|
data/lib/ramekin/renderer.rb
CHANGED
@@ -74,13 +74,17 @@ module Ramekin
|
|
74
74
|
yield "; https://codeberg.org/jneen/ramekin\n\n"
|
75
75
|
|
76
76
|
# TODO
|
77
|
-
yield "#amk 2\n\n"
|
77
|
+
yield "#amk #{@track.meta.amk&.value || 2}\n\n"
|
78
78
|
|
79
79
|
if m.instruments.any?
|
80
80
|
yield "#path #{@filename.chomp('.rmk').inspect}\n"
|
81
81
|
yield "#samples {\n"
|
82
|
-
m.sample_groups.
|
83
|
-
yield "
|
82
|
+
if m.sample_groups.empty?
|
83
|
+
yield " #default"
|
84
|
+
else
|
85
|
+
m.sample_groups.each do |group|
|
86
|
+
yield " ##{group.value}\n"
|
87
|
+
end
|
84
88
|
end
|
85
89
|
|
86
90
|
m.instruments.map(&:sample_name).sort.uniq.each do |sample|
|
@@ -170,13 +174,7 @@ module Ramekin
|
|
170
174
|
# reset tick counter for newlines
|
171
175
|
@tick = 0
|
172
176
|
when :transpose
|
173
|
-
|
174
|
-
|
175
|
-
if interval < 0
|
176
|
-
interval = 0x80 - interval
|
177
|
-
end
|
178
|
-
|
179
|
-
yield sprintf("$fa$02$%02x", token.value.to_i)
|
177
|
+
yield sprintf("$fa$02$%02x", token.value.to_i & 0x7f)
|
180
178
|
when :instrument
|
181
179
|
case token.value
|
182
180
|
when /\A\d+\z/ then yield "@#{token.value}"
|
@@ -189,11 +187,12 @@ module Ramekin
|
|
189
187
|
yield "@#{@instrument_index[token.value]}"
|
190
188
|
end
|
191
189
|
when :v
|
192
|
-
|
193
|
-
|
190
|
+
vol, time = token.values.compact.map(&:to_i)
|
191
|
+
yield velocity_command(vol, time)
|
192
|
+
@volume = vol
|
194
193
|
when :relv
|
195
194
|
relvol, duration = token.values
|
196
|
-
yield
|
195
|
+
yield velocity_command(@volume + relvol.to_i, duration)
|
197
196
|
when :adsr
|
198
197
|
vals = token.value.split(',').map { |x| x.to_i(16) }
|
199
198
|
error! 'invalid #adsr, expected 4 arguments' unless vals.size == 4
|
@@ -254,6 +253,20 @@ module Ramekin
|
|
254
253
|
end
|
255
254
|
end
|
256
255
|
|
256
|
+
def velocity_command(vol, time=nil)
|
257
|
+
vol = 255 if vol > 255
|
258
|
+
vol = 0 if vol < 0
|
259
|
+
|
260
|
+
if time.nil?
|
261
|
+
"v#{vol}"
|
262
|
+
else
|
263
|
+
time = time.to_i
|
264
|
+
time = 255 if time > 255
|
265
|
+
time = 0 if time < 0
|
266
|
+
sprintf("$E8$%02x$%02x", time, vol)
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
257
270
|
def render_directive(token)
|
258
271
|
case token.value
|
259
272
|
when 'SPC'
|
data/lib/ramekin/sample_pack.rb
CHANGED
@@ -105,6 +105,10 @@ module Ramekin
|
|
105
105
|
File.join(prefix_dir, "#{path}.brr")
|
106
106
|
end
|
107
107
|
|
108
|
+
def has?(path)
|
109
|
+
File.exist?(find(path))
|
110
|
+
end
|
111
|
+
|
108
112
|
def tunings_for(path)
|
109
113
|
rel = Pathname.new(find(path)).relative_path_from(dir).to_s
|
110
114
|
(tunings[rel] || []).map(&:last)
|
data/lib/ramekin/spc_player.rb
CHANGED
@@ -37,7 +37,7 @@ module Ramekin
|
|
37
37
|
File.exist?("#@spcplay_dir/spcplay.exe")
|
38
38
|
end
|
39
39
|
|
40
|
-
def play(fname)
|
40
|
+
def play(fname, offset_=0)
|
41
41
|
fname = File.expand_path(fname)
|
42
42
|
Dir.chdir(@spcplay_dir) do
|
43
43
|
sys "spcplay.exe", fname
|
@@ -61,8 +61,8 @@ module Ramekin
|
|
61
61
|
end
|
62
62
|
|
63
63
|
class NormalSPCPlayer < SPCPlayer
|
64
|
-
def play(fname)
|
65
|
-
sys "#@spct_dir/spct", 'play', fname
|
64
|
+
def play(fname, offset=0)
|
65
|
+
sys "#@spct_dir/spct", 'play', fname, '--seek', offset
|
66
66
|
end
|
67
67
|
|
68
68
|
def render(fname, outfile, seconds=nil)
|
@@ -110,9 +110,9 @@ module Ramekin
|
|
110
110
|
sys(*args)
|
111
111
|
end
|
112
112
|
|
113
|
-
def play(fname)
|
113
|
+
def play(fname, offset=0)
|
114
114
|
if File.basename(@path, '.exe') == 'spct'
|
115
|
-
sys @path, 'play', fname
|
115
|
+
sys @path, 'play', fname, '--seek', offset
|
116
116
|
else
|
117
117
|
sys @path, fname
|
118
118
|
end
|
data/lib/ramekin/tokenizer.rb
CHANGED
@@ -135,9 +135,9 @@ module Ramekin
|
|
135
135
|
newlines = matched.count("\n")
|
136
136
|
@line += newlines
|
137
137
|
if newlines > 0
|
138
|
-
@col = find_colno(matched
|
138
|
+
@col = find_colno(matched)
|
139
139
|
else
|
140
|
-
@col += find_colno(matched
|
140
|
+
@col += find_colno(matched)
|
141
141
|
end
|
142
142
|
end
|
143
143
|
|
@@ -208,6 +208,7 @@ module Ramekin
|
|
208
208
|
return [:endif, m(1)] if match /#endif/
|
209
209
|
|
210
210
|
return [:adsr, m(1)] if match /#adsr:(\h+(?:,\h+)*)/
|
211
|
+
return [:gain, m(1)] if match /#gain:(\h+)/
|
211
212
|
return [:tuning, m(1)] if match /#tuning:(\h\h\h\h)/
|
212
213
|
return [:bpm, m(1)] if match /#bpm:(\d+)/
|
213
214
|
return [:legato_tie] if match /~/
|
@@ -259,7 +260,7 @@ module Ramekin
|
|
259
260
|
return [:q, m(1)] if match /q(\h\h)/
|
260
261
|
return [:n, m(1)] if match /n(\h\h?)/
|
261
262
|
|
262
|
-
error! "unknown token near: #{@scanner.peek(10)}"
|
263
|
+
error! "unknown token near: #{@scanner.peek(10)}", el: @last_token
|
263
264
|
|
264
265
|
return [:unknown, m] if match /./
|
265
266
|
end
|
data/lib/ramekin/util.rb
CHANGED
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.8
|
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-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: strscan
|