ramekin 0.0.7 → 0.0.8

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 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