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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c8ecaeee8d7551d229bd4d659e37db4fb7ce51b8c8b02db5951afe2889c5766d
4
- data.tar.gz: 306dd97179707ab87cbf615c0740495f230a5be78476c89855c5e65c3cbc8d54
3
+ metadata.gz: 463b021dd0273151c13a7590db845acf584a2df021596dd715721964e777f6d9
4
+ data.tar.gz: 432c1eccc9c5443cc63ec828f87a319141caeb3080c847948634b7935553ec86
5
5
  SHA512:
6
- metadata.gz: f6496a57a0d10da8cb22d3c0da7593fc8db6949f36fa78b6bf124b39bb727f9b05176fff29961111f510029c7ec93e7d4b8edad2ee0704e312bff82b2d5b02e0
7
- data.tar.gz: 494634f3636b32f99fd77c3337b7981021f39850aee811cbe15e6b8154fe5d1474ca51659bce91fe46e09ec4e64e7d5344488ba171523b5036ca7e53713cfcf5
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
@@ -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, @current, name, path, extensions)
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
- if channels == 'all'
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
 
@@ -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.each do |group|
83
- yield " ##{group.value}\n"
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
- interval = token.value.to_i
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
- yield "v#{token.values.compact.join(',')}"
193
- @volume = token.values[0].to_i
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 "v#{[@volume + relvol.to_i, duration].compact.join(',')}"
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'
@@ -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)
@@ -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
@@ -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[0])
138
+ @col = find_colno(matched)
139
139
  else
140
- @col += find_colno(matched[0])
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
@@ -44,7 +44,7 @@ module Ramekin
44
44
  env = {}
45
45
  kw.each { |k, v| env[k.to_s] = v }
46
46
 
47
- system(env, *a)
47
+ system(env, *a.map(&:to_s))
48
48
  rescue Interrupt
49
49
  # allow interrupt out of the subprocess but capture it for ramekin itself
50
50
  end
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.7
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-17 00:00:00.000000000 Z
11
+ date: 2025-02-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: strscan