ramekin 0.0.7 → 0.0.9

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: 1454704618e8123c1ade7251f1a30cc66b2f2febacd10e1e8f438e4b3fe3023c
4
+ data.tar.gz: 82453a74e36685f30e7637092fc47d242a63b609c7e4b1f586b17fafae05289f
5
5
  SHA512:
6
- metadata.gz: f6496a57a0d10da8cb22d3c0da7593fc8db6949f36fa78b6bf124b39bb727f9b05176fff29961111f510029c7ec93e7d4b8edad2ee0704e312bff82b2d5b02e0
7
- data.tar.gz: 494634f3636b32f99fd77c3337b7981021f39850aee811cbe15e6b8154fe5d1474ca51659bce91fe46e09ec4e64e7d5344488ba171523b5036ca7e53713cfcf5
6
+ metadata.gz: f33e028002e58ad86ae808bcc4a0a77b9c8b324e3a47f652bf20dcf1bc4a83381f13e23e3ec980f5350cad8686f13097f1996e08c3de798614e4092ca55a8cbf
7
+ data.tar.gz: 4df89465d887a660c7353a6e4b16e3817603efd861c60315c39ca531026af27b5a72bf0a7b32aa73328f9b0160f3f7f5aa868a2de9fbe6bf493bb4f1cc345aff
data/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  Ramekin is a pre-processor for AddMusicK syntax that is in very early development.
4
4
 
5
+ Please keep in mind that as alpha software, **I may make breaking changes at any time.** After initial testing is done, I will release 1.0.0, at which point I will make a reasonable commitment to back-compatibility. That time is not yet.
6
+
5
7
  # Installation
6
8
 
7
9
  First, [Install Ruby](https://ruby-lang.org). Windows users can use [RubyInstaller](https://rubyinstaller.org/).
@@ -210,6 +212,24 @@ After the instrument declaration, you can use several commands to change the def
210
212
 
211
213
  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
214
 
215
+ ### Echo settings
216
+
217
+ Echo settings can be set up with the `#echo/...` family of directives:
218
+
219
+ ```elisp
220
+ #echo/channels:0,1,2,3
221
+ ; or
222
+ #echo/channels:all
223
+ ; or
224
+ #echo/channels:none
225
+
226
+ #echo/volume:20 ; range from -7f to 80, use negatives for surround
227
+ #echo/volume:20,30 ; set different values for left vs right echo
228
+ #echo/feedback:48 ; range from -7f to 80, use negatives for surround
229
+ #echo/fir:1 ; 1 or 0 to enable/disable the FIR filter
230
+ ```
231
+
232
+
213
233
  ## Channel Commands
214
234
 
215
235
  With your metadata all set up, it's time to add some notes!
@@ -3,6 +3,8 @@ require_relative 'amk_runner/sample_groups'
3
3
 
4
4
  module Ramekin
5
5
  class AMKRunner
6
+ include Util
7
+
6
8
  def initialize(filename, meta, txt)
7
9
  @filename = File.expand_path(filename)
8
10
  @amk_path = Ramekin.config.amk_dir
@@ -40,6 +42,8 @@ module Ramekin
40
42
 
41
43
  ln("#@amk_path/asm", "#@workdir/asm")
42
44
 
45
+ FileUtils.mkdir_p("#@workdir/Visualizations")
46
+
43
47
  FileUtils.mkdir_p("#@workdir/samples")
44
48
  ln("#@amk_path/samples/default", "#@workdir/samples/default")
45
49
  ln("#@amk_path/samples/optimized", "#@workdir/samples/optimized")
@@ -62,7 +66,7 @@ module Ramekin
62
66
  File.write("#@workdir/Addmusic_sound effects.txt", '')
63
67
 
64
68
  Dir.chdir(@workdir) do
65
- system "./AddmusicK -norom ramekin/#{basename}.txt"
69
+ sys './AddmusicK', '-norom', '-visualize', "ramekin/#{basename}.txt"
66
70
  res = $?
67
71
  binding.pry unless res.success?
68
72
  end
@@ -73,6 +77,7 @@ module Ramekin
73
77
  FileUtils.cp(@filename, "./#{basename}.rmk")
74
78
  FileUtils.cp(spc_file, "./#{basename}.spc")
75
79
  FileUtils.cp(stats_file, "./#{basename}.stats.txt")
80
+ FileUtils.cp("#@workdir/Visualizations/#{basename}.png", "./#{basename}.png")
76
81
  File.write("./#{basename}.txt", @txt)
77
82
 
78
83
  FileUtils.mkdir_p("samples/#{basename}")
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'
@@ -134,7 +139,7 @@ module Ramekin
134
139
  # have a path to render the SPC file to.
135
140
  if @play || @wav_file
136
141
  if @output_package
137
- @play_spc = "#@output_package/#{File.basename(@infile)}.spc"
142
+ @play_spc = "#@output_package/#{File.basename(@infile, '.rmk')}.spc"
138
143
  elsif @output_spc
139
144
  @play_spc = @output_spc
140
145
  else
@@ -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|
@@ -109,7 +113,7 @@ module Ramekin
109
113
  def tempo_of(el)
110
114
  case el.type
111
115
  when :t then el.value
112
- when :bpm then (el.value.to_i * 256 / 625.0).round
116
+ when :bpm then (el.value.to_i * 8192 / 20025.0).round
113
117
  end
114
118
  end
115
119
 
@@ -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,14 @@ 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)
196
+ when :q
197
+ yield "q#{token.value}"
197
198
  when :adsr
198
199
  vals = token.value.split(',').map { |x| x.to_i(16) }
199
200
  error! 'invalid #adsr, expected 4 arguments' unless vals.size == 4
@@ -254,6 +255,20 @@ module Ramekin
254
255
  end
255
256
  end
256
257
 
258
+ def velocity_command(vol, time=nil)
259
+ vol = 255 if vol > 255
260
+ vol = 0 if vol < 0
261
+
262
+ if time.nil?
263
+ "v#{vol}"
264
+ else
265
+ time = time.to_i
266
+ time = 255 if time > 255
267
+ time = 0 if time < 0
268
+ sprintf("$E8$%02x$%02x", time, vol)
269
+ end
270
+ end
271
+
257
272
  def render_directive(token)
258
273
  case token.value
259
274
  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 /~/
@@ -227,6 +228,7 @@ module Ramekin
227
228
  return [:instrument, m(1)] if match /@(\w+)/
228
229
  return [:hex, m(1)] if match /[$](\h\h)/
229
230
  return [:t, m(1)] if match /t(\d+)/
231
+ return [:q, m(1)] if match /q(\d\h?)/
230
232
 
231
233
  return note(:note, m) if match /[abcdefg][+-]?/
232
234
  return note(:r) if match /r/
@@ -259,7 +261,7 @@ module Ramekin
259
261
  return [:q, m(1)] if match /q(\h\h)/
260
262
  return [:n, m(1)] if match /n(\h\h?)/
261
263
 
262
- error! "unknown token near: #{@scanner.peek(10)}"
264
+ error! "unknown token near: #{@scanner.peek(10)}", el: @last_token
263
265
 
264
266
  return [:unknown, m] if match /./
265
267
  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.9
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