ramekin 0.0.5b

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 42635a3432e6ba8fc0f53454dab984170902a215d2530834278b7c70e088b354
4
+ data.tar.gz: 265b13b18ce9a6840a5d550e675b2ed20d417d95edf01af57467a2b8cdd83c95
5
+ SHA512:
6
+ metadata.gz: 5740cf99c3ba2ec568c2075d1ba40ee96a790c3617638e7c17f293051a0ad02803e4ebe7f20e8f76315050b2cfb55149918932eddad3675c3613795529b5f686
7
+ data.tar.gz: a42be3e89c445f84639fcbc963a199a9ebaf84b174dde945526914a49b881ca2b74ad8ee346527c2ffb460deb1a5a4ff3c331842d989a730807ca6dce61992a6
data/README.md ADDED
@@ -0,0 +1,277 @@
1
+ # Ramekin
2
+
3
+ Ramekin is a pre-processor for AddMusicK syntax that is in very early development.
4
+
5
+ # Installation
6
+
7
+ 1. [Install Ruby](https://ruby-lang.org). Windows users can use [RubyInstaller](https://rubyinstaller.org/).
8
+ 2. [Download the script](https://codeberg.org/jneen/ramekin/releases).
9
+ 3. Install the scripts:
10
+ - For Windows users, put both `ramekin` and `ramekin.bat` in `%LOCALAPPDATA\Microsoft\WindowsApps\`.
11
+ - For MacOS and Linux users, ignore `ramekin.bat` - make the script executable with `chmod +x` and put it somewhere on your PATH.
12
+ 4. Run `ramekin setup` to set up dependencies and download sample packs. You will need about 90M of free space.
13
+
14
+ # Usage
15
+
16
+ ```
17
+ usage: ramekin [command] [flags]
18
+ (default command: compile)
19
+
20
+ ramekin compile -i filename.rmk [flags]
21
+ flags:
22
+ -h --help
23
+ display this message
24
+ -i filename.rmk
25
+ set the input file
26
+ --txt filename.txt
27
+ output amk txt to this file
28
+ --spc filename.spc
29
+ attempt to invoke AddmusicK to output an SPC
30
+ requires ADDMUSICK_DIR and ASAR_COMMAND
31
+ to be set.
32
+ --play
33
+ play the generated SPC file. will automatically
34
+ set up an SPC player if none is detected.
35
+ --wav filename.wav
36
+ --wav filename.wav:N
37
+ (non-windows only)
38
+ render N seconds of the file to WAV.
39
+
40
+ ramekin package [flags]
41
+ flags:
42
+ --update
43
+ download BRR packages from SMW Central.
44
+ --search [text]
45
+ search for BRR filenames.
46
+ --list [text]
47
+ list all samples in packages matching [text].
48
+
49
+ ramekin setup [flags]
50
+ flags:
51
+ --amk
52
+ downloads and sets up AddMusicK and asar.
53
+ (requires cmake and make to be available)
54
+ --packages
55
+ downloads packages from SMW Central.
56
+ (equivalent to package --update)
57
+ --spc
58
+ downloads and sets up a default SPC player.
59
+ --all (default)
60
+ runs all of the above setup steps
61
+ --force
62
+ deletes and redownloads files instead of skipping.
63
+ ```
64
+
65
+ # Configuration
66
+
67
+ The first time ramekin runs, it will create a configuration file in `~/.ramekin/config.yml` (where `~` is your [home directory](https://en.wikipedia.org/wiki/Home_directory)). Edit this file with your favourite text editor, and be sure to remove the `#` from the start of lines you want to take effect. If you want Ramekin to keep its files in some other place, override the `RAMEKIN_HOME` environment variable.
68
+
69
+ # If you already know AddmusicK
70
+
71
+ A list of some ramekin preprocessor features (see `spec/rmk` for some examples!):
72
+
73
+ * The metadata section (before any channels) is fairly different, I recommend reading the metadata part of the guide below.
74
+ * Macros ("replacements") are implemented in a much more robust way (*with* tokenization), and can no longer interrupt other tokens. The generated txt will not contain any replacements.
75
+ * Adopted the transposition syntax `_+N`, `_-N`, and `_0` from General MML. Compiles to `$fa$02$XX`.
76
+ * `#adsr:A,D,S,RR` syntax for ADSR. Also usable on an `#instrument` declaration, with the same syntax. A, D, and R are flipped so that higher numbers are longer times.
77
+ * `v+X` and `v-X` are volumes relative to the last `vXXX` command. Useful for separating expression from mixing.
78
+ * `yLX` and `yRX` commands for panning left and right. `yC` to set back to center. Way easier for me to remember.
79
+ * `#bend` followed by a note with any length, including ties, will bend for that note's duration. Continue the note with a non-collapsing tie `^^`. Octave changes, `l` commands, and other note modifiers are allowed here. This will compile to a correct `$DD` command.
80
+ ```elisp
81
+ ; bends to c two octaves up for two 16th notes, then continues for a quarter note
82
+ b8 #bend >>c16^16 ^^4
83
+ ```
84
+ * Instruments are named rather than numbered. See `doc/smw-instruments.rmk` for a list.
85
+ * Switching instruments always sets that instrument's default octave, by default `o4`. It does *not* reset transposition (you can use `_0` for that).
86
+ * Samples are loaded directly from SMWCentral using `#pack` syntax:
87
+
88
+ ```elisp
89
+ ; references the BRR pack "Chrono Trigger" from SMW Central
90
+ #pack "Chrono Trigger"
91
+
92
+ ; declares an instrument @kick with tuning parameters parsed from the BRR pack
93
+ #instrument @kick "Kick"
94
+
95
+ ; parameters and default octave can be overridden
96
+ #instrument @crash "Crash Cymbal" o4 #tuning:1FBC #adsr:0,0,7,1F
97
+ ```
98
+
99
+ * In ramekin, there is no difference between instrument `#adsr` syntax and the one in the pattern data. They are both compiled to their respective syntaxes in the txt.
100
+
101
+ * Tempo can alternately be declared with `#bpm:128`. This will be converted to the nearest `tXX` command. A major TODO is automatic `#halvetempo` etc.
102
+ * `p0,0` compiles to `$df`.
103
+ * "Legato tie" represented by `~`, which will use `$f4$01` at appropriate times to cause the note transition to be played legato.
104
+ * If you ever want to see what exactly Ramekin is generating, just use `--txt` and you can inspect the generated AddmusicK syntax manually!
105
+
106
+ # Syntax
107
+
108
+ Ramekin syntax is very similar to AddmusicK syntax. Comments begin with `;` and span to the end of the line, and most commands are either single characters, or directives marked with `#`.
109
+
110
+ ## Metadata / preamble
111
+
112
+ The top of a Ramekin file, before the first channel is declared, is the *preamble*. Here, various commands can be used, starting with `#`.
113
+
114
+ ### Metadata commands
115
+
116
+ These commands set important metadata headers for the SPC.
117
+
118
+ ```elisp
119
+ #title "My cool songle"
120
+ #game "title of the game, if any"
121
+ #author "my name"
122
+ #comment "usually something about who ported the track"
123
+ ```
124
+
125
+ Additionally, you can specify additional `#readme` text to be included in the packaged song:
126
+
127
+ ```elisp
128
+ #readme "
129
+ Here is some very important information about running this track.
130
+ "
131
+ ```
132
+
133
+ Finally, some general options can be set:
134
+
135
+ ```elisp
136
+ ; causes the track not to speed up when the timer is low
137
+ #option TempoImmunity
138
+
139
+ ; sets the global volume, 0-255.
140
+ ; Try to aim for -21 to -19 lufs to balance well with sound effects.
141
+ w150
142
+
143
+ ; sets the bpm. (todo: mention the reasonable range for this)
144
+ #bpm:130
145
+
146
+ ; echo settings. this syntax is likely to change in the future, because it sucks
147
+ #echo $ef$ff$df$df $f1$02$cf$01
148
+ ```
149
+
150
+ ### Instrument definitions
151
+
152
+ #### Default Instruments
153
+
154
+ Ramekin can use the `#default` and `#optimized` native sample groups for SMW. One of these directives must be included for sound effects to work properly in the game. Using native SMW instruments is the easiest way to get started quickly.
155
+
156
+ The `#default` sample group is implied if nothing else is specified, but you can use `#optimized` if you are running low on ARAM (more on that later).
157
+
158
+ To see the full list of available native instruments, see `doc/smw-instruments.rmk`
159
+
160
+ #### Sample Packs
161
+
162
+ To get more diverse sounds on the SNES, it is often nice to use samples, either ripped from other games or converted to BRR (the SNES's native sample format).
163
+
164
+ Ramekin allows you to extremely easily use BRR packs from SMW Central's repositories. These not only contain BRR samples, but also the tuning and ADSR data to make them sound great by default.
165
+
166
+ To load a pack from SMW Central, use `#pack` with the pack's name on SMW Central. For example, let's say I wanted to use samples from Chrono Trigger. I can search that with:
167
+
168
+ ```console
169
+ ramekin package --list chrono
170
+ ```
171
+
172
+ This will show us a pack named "Chrono Trigger" along with a bunch of files with a `.brr` extension. To use the pack, add:
173
+
174
+ ```elisp
175
+ #pack "Chrono Trigger"
176
+ ```
177
+
178
+ Then, to load, say, the sitar from the pack, we use:
179
+
180
+ ```elisp
181
+ #instrument @sitar "Sitar.brr"
182
+ ```
183
+
184
+ This defines a new instrument called `@sitar` to point to `Sitar.brr` with the default settings. You can also leave off the ".brr" extension if you like. Later, you can use the command `@sitar` to switch to this instrument.
185
+
186
+ After the instrument declaration, you can use several commands to change the default settings, such as `#adsr`, `#tuning` and `o`:
187
+
188
+ ```elisp
189
+ #instrument @sitar #adsr:0,4,2,23 #tuning:1a2f o5
190
+ ```
191
+
192
+ 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.
193
+
194
+ ## Channel Commands
195
+
196
+ With your metadata all set up, it's time to add some notes!
197
+
198
+ SNES audio is organized into 8 channels, numbered 0-7. But in the context of a romhack, channels 6 and 7 are reserved for sound effects.
199
+
200
+ **This is the biggest limitation of romhack music: You must generally arrange your music to fit on 6 channels.** Each channel can only play one note at a time - for chords, you must use multiple channels. However, channels can switch instruments extremely quickly - so things can be interleaved if you are clever with instrument switches.
201
+
202
+ ### Notes
203
+
204
+ To start adding notes to a channel, use `#N`, where N is the channel number:
205
+
206
+ ```elisp
207
+ #0
208
+ ; now we're in channel 0!
209
+ ```
210
+
211
+ Next, switch to an instrument, and add some notes:
212
+
213
+ ```elisp
214
+ #0
215
+ @smwacousticbass
216
+ o3
217
+ c8d8e8f8
218
+ ```
219
+
220
+ this plays 8th notes c, d, e, and f in octave 3 on the instrument `@smwacousticbass`.
221
+
222
+ For sharps and flats, use `+` and `-`, and for rests, use the special note `r`:
223
+
224
+ ```elisp
225
+ #0 @smwacousticbass o5
226
+ d8 e-8 f+8 g8 r2
227
+ ```
228
+
229
+ This plays d, e-flat, f-sharp, g in 8th notes, followed by a half-note rest. To convert this to an spc, save this to a file named `my-cool-song.rmk`, and run
230
+
231
+ ```
232
+ ramekin my-cool-song.rmk --spc my-cool-song.spc
233
+ ```
234
+
235
+ This will create a file called `my-cool-song.spc`, which you can open with an SPC player. Notice that it loops to the beginning by default! The default behaviour of the AddMusicK/smw music system is to loop as soon as the first defined channel runs out of notes.
236
+
237
+ To set the loop point somewhere that is not the beginning, use the `/` command:
238
+
239
+ ```elisp
240
+ ; will return to the / when it hits the loop point
241
+ #0 @smwacousticbass o5
242
+ d8 e-8 / f+8 g8 r2
243
+ ```
244
+
245
+ For more complex note lengths, **dots** and **ties** are available. For example, `b8.` plays a `b` for a dotted eigth note length. This is equivalent to `b8^16`, which plays for an 8th note tied to a 16th note.
246
+
247
+ Because it is common to play a bunch of fast notes all the same length, the `l` command allows setting a default length to use when no note length is specified. So our example from before is equivalent to:
248
+
249
+ ```elisp
250
+ #0 @smwacousticbass o5
251
+ l8 de-f+g r2
252
+ ```
253
+
254
+ Personally, I tend to use `l16` across the whole track for consistency.
255
+
256
+ ### Loops and loop calls
257
+
258
+ Just as in Addmusick, there are two kinds of loops:
259
+
260
+ * Regular loops, marked with `[ ]`, which can optionally be tagged with a number, as in `(1)[ ]`. These can not only loop immediately but also be called at arbitrary points.
261
+ * Super loops, marked with `[[ ]]`, which can only loop immediately, but can nest either inside or outside of regular loops.
262
+
263
+ This is best shown with an example:
264
+
265
+ ```elisp
266
+ #0 @smwacousticbass l16
267
+ [ defg ]4 ; plays defg four times (regular loop)
268
+ [[ abcd ]]4 ; plays abcd four times (superloop)
269
+ * ; calls the last defined regular loop, in this case plays defg
270
+ (01)[ fedc ] ; defines a loop named (01), also plays fedc immediately
271
+ (01) ; calls the loop (01)
272
+ (01)2 ; calls the loop (01) twice
273
+ ```
274
+
275
+ ### Expression and effects
276
+
277
+ Volume can be set with `vXXX`, where `XXX` is a number between 0 and 255.
data/gembin/ramekin ADDED
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # Editable default configs.
4
+ # These can be edited by packagers or by you if you're feeling spicy.
5
+ # You can also override these values with environment variables (of the same name),
6
+ # or with a file `config.yml` in RAMEKIN_HOME.
7
+ RAMEKIN_HOME = '~/.ramekin'
8
+ RAMEKIN_AMK_DIR = './addmusick'
9
+ RAMEKIN_ASAR_DIR = './asar'
10
+ RAMEKIN_SPC_PLAYER = '__auto__'
11
+ RAMEKIN_VERSION = Gem.loaded_specs['ramekin'].version.to_s
12
+
13
+ require_relative '../lib/ramekin'
14
+ require_relative '../lib/ramekin/cli'
15
+
16
+ Ramekin::CLI.main(*ARGV)
@@ -0,0 +1,65 @@
1
+ SAMPLE_GROUPS = <<~'___'
2
+ #default
3
+ {
4
+ "default/00 SMW @0.brr"!
5
+ "default/01 SMW @1.brr"!
6
+ "default/02 SMW @2.brr"!
7
+ "default/03 SMW @3.brr"!
8
+ "default/04 SMW @4.brr"!
9
+ "default/05 SMW @8.brr"!
10
+ "default/06 SMW @22.brr"!
11
+ "default/07 SMW @5.brr"!
12
+ "default/08 SMW @6.brr"!
13
+ "default/09 SMW @7.brr"!
14
+ "default/0A SMW @9.brr"!
15
+ "default/0B SMW @10.brr"!
16
+ "default/0C SMW @13.brr"!
17
+ "default/0D SMW @14.brr"
18
+ "default/0E SMW @29.brr"!
19
+ "default/0F SMW @21.brr"
20
+ "default/10 SMW @12.brr"!
21
+ "default/11 SMW @17.brr"
22
+ "default/12 SMW @15.brr"!
23
+ "default/13 SMW Thunder.brr"!
24
+ }
25
+
26
+ #optimized
27
+ {
28
+ "optimized/00 SMW @0.brr"!
29
+ "optimized/01 SMW @1.brr"!
30
+ "optimized/02 SMW @2.brr"!
31
+ "optimized/03 SMW @3.brr"!
32
+ "optimized/04 SMW @4.brr"!
33
+ "optimized/05 SMW @8.brr"!
34
+ "optimized/06 SMW @22.brr"!
35
+ "optimized/07 SMW @5.brr"!
36
+ "optimized/08 SMW @6.brr"!
37
+ "optimized/09 SMW @7.brr"!
38
+ "optimized/0A SMW @9.brr"!
39
+ "optimized/0B SMW @10.brr"!
40
+ "optimized/0C SMW @13.brr"!
41
+ "optimized/0D SMW @14.brr"
42
+ "optimized/0E SMW @29.brr"!
43
+ "optimized/0F SMW @21.brr"
44
+ "optimized/10 SMW @12.brr"!
45
+ "optimized/11 SMW @17.brr"
46
+ "optimized/12 SMW @15.brr"!
47
+ "optimized/13 SMW Thunder.brr"!
48
+ }
49
+
50
+ #AMM
51
+ {
52
+ "EMPTY.brr"!
53
+ "EMPTY.brr"
54
+ "EMPTY.brr"
55
+ "EMPTY.brr"
56
+ "EMPTY.brr"
57
+ "EMPTY.brr"
58
+ "EMPTY.brr"
59
+ "EMPTY.brr"
60
+ "EMPTY.brr"
61
+ "EMPTY.brr"
62
+ "EMPTY.brr"
63
+ "EMPTY.brr"
64
+ }
65
+ ___
@@ -0,0 +1,123 @@
1
+ require 'fileutils'
2
+ require_relative 'amk_runner/sample_groups'
3
+
4
+ module Ramekin
5
+ class AMKRunner
6
+ def initialize(filename, meta, txt)
7
+ @filename = File.expand_path(filename)
8
+ @amk_path = Ramekin.config.amk_dir
9
+ AMKSetup.setup! unless AMKSetup.setup_ok?
10
+ @meta = meta
11
+ @txt = txt
12
+ @workdir = Dir.mktmpdir
13
+ end
14
+
15
+ def basename
16
+ File.basename(@filename).chomp('.rmk')
17
+ end
18
+
19
+ def ln(src, dest)
20
+ # windows permissions don't allow linking from temp dirs
21
+ if Ramekin.config.windows?
22
+ FileUtils.cp_r(src, dest)
23
+ else
24
+ FileUtils.ln_s(src, dest)
25
+ end
26
+ end
27
+
28
+ def compile
29
+ FileUtils.mkdir_p("#@workdir/music/ramekin")
30
+ FileUtils.mkdir_p("#@workdir/SPCs")
31
+ FileUtils.mkdir_p("#@workdir/stats")
32
+
33
+ if Ramekin.config.windows?
34
+ ln("#@amk_path/AddmusicK.exe", "#@workdir/AddmusicK.exe")
35
+ ln("#@amk_path/asar.dll", "#@workdir/asar.dll")
36
+ else
37
+ ln("#@amk_path/AddmusicK", "#@workdir/AddmusicK")
38
+ ln(Ramekin.config.asar_lib, "#@workdir/libasar.#{Ramekin.config.lib_ext}")
39
+ end
40
+
41
+ ln("#@amk_path/asm", "#@workdir/asm")
42
+
43
+ FileUtils.mkdir_p("#@workdir/samples")
44
+ ln("#@amk_path/samples/default", "#@workdir/samples/default")
45
+ ln("#@amk_path/samples/optimized", "#@workdir/samples/optimized")
46
+ ln("#@amk_path/samples/EMPTY.brr", "#@workdir/samples/EMPTY.brr")
47
+ if @meta.instruments.any?
48
+ sample_dir = "#@workdir/samples/#{basename}"
49
+ FileUtils.mkdir_p(sample_dir)
50
+
51
+ @meta.instruments.each do |inst|
52
+ ln(inst.sample_path, "#{sample_dir}/#{inst.sample_name}")
53
+ end
54
+ end
55
+
56
+ File.write("#@workdir/music/ramekin/#{basename}.txt", @txt)
57
+ File.write("#@workdir/Addmusic_sample groups.txt", SAMPLE_GROUPS)
58
+ File.write("#@workdir/Addmusic_list.txt", <<~___)
59
+ Globals:
60
+ 01 ramekin/#{basename}.txt
61
+ ___
62
+ File.write("#@workdir/Addmusic_sound effects.txt", '')
63
+
64
+ Dir.chdir(@workdir) do
65
+ system "./AddmusicK -norom ramekin/#{basename}.txt"
66
+ res = $?
67
+ binding.pry unless res.success?
68
+ end
69
+ end
70
+
71
+ def export(outdir)
72
+ Dir.chdir outdir do
73
+ FileUtils.cp(@filename, "./#{basename}.rmk")
74
+ FileUtils.cp(spc_file, "./#{basename}.spc")
75
+ FileUtils.cp(stats_file, "./#{basename}.stats.txt")
76
+ File.write("./#{basename}.txt", @txt)
77
+
78
+ FileUtils.mkdir_p("samples/#{basename}")
79
+ @meta.instruments.each do |inst|
80
+ FileUtils.cp(inst.sample_path, "./samples/#{basename}/#{inst.sample_name}")
81
+ end
82
+
83
+ packs = @meta.instruments.map(&:pack).uniq
84
+
85
+ pack_info = packs.map do |pack|
86
+ out = StringIO.new
87
+ out << " #{pack.name}"
88
+ out << " (posted by #{pack.authors.join(', ')})" if pack.authors.any?
89
+ out << "\n"
90
+
91
+ out << " - #{pack.url}"
92
+ out.string
93
+ end.join("\n\n")
94
+
95
+ readme = @meta.readme&.value || '(you should edit this space before publishing)'
96
+
97
+ File.write("./README.txt", <<~README)
98
+ #{readme}
99
+
100
+ --
101
+
102
+ #{basename}.txt was composed as #{basename}.rmk with Ramekin
103
+ https://codeberg.org/jneen/ramekin
104
+
105
+ Sample sources:
106
+ #{pack_info}
107
+ README
108
+ end
109
+ end
110
+
111
+ def spc_file
112
+ "#@workdir/SPCs/#{basename}.spc"
113
+ end
114
+
115
+ def stats_file
116
+ "#@workdir/stats/#{basename}.txt"
117
+ end
118
+
119
+ def spc
120
+ File.read(spc_file)
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,116 @@
1
+ require 'uri'
2
+ require 'open-uri'
3
+ require 'json'
4
+
5
+ module Ramekin
6
+ module AMKSetup
7
+ def self.setup!(**opts)
8
+ Dir.chdir(HOME) do
9
+ if Ramekin.config.windows?
10
+ WindowsSetup.new(**opts).setup!
11
+ else
12
+ NormalSetup.new(**opts).setup!
13
+ end
14
+ end
15
+ end
16
+
17
+ def self.setup_ok?
18
+ if Ramekin.config.windows?
19
+ File.exist?("#{Ramekin.config.amk_dir}/AddmusicK.exe")
20
+ else
21
+ Ramekin.config.try_asar_lib && File.executable?("#{Ramekin.config.amk_dir}/Addmusick")
22
+ end
23
+ end
24
+
25
+ class Setup
26
+ include Util
27
+
28
+ def initialize(force: false)
29
+ @force = force
30
+ end
31
+
32
+ def error!(msg)
33
+ $stderr.puts(msg)
34
+ exit 1
35
+ end
36
+
37
+ def latest_tag(repo, host='github.com')
38
+ host = 'api.github.com' if host == 'github.com'
39
+ host = 'codeberg.org/api/v1' if host == 'codeberg.org'
40
+
41
+ tag_info = JSON.parse(URI.open("https://#{host}/repos/#{repo}/git/refs/tags").read)
42
+ tag_info.last['ref']
43
+ end
44
+
45
+ def unpack_repo_source!(repo, dir, host: 'github.com')
46
+ clear_dir(dir, force: @force) or return false
47
+
48
+ tag = latest_tag(repo, host)
49
+ tag = File.basename(tag) if host == 'codeberg.org'
50
+
51
+ source_url = "https://#{host}/#{repo}/archive/#{tag}.zip"
52
+
53
+ Dir.chdir(dir) do
54
+ zip = URI.open(source_url).read
55
+ $stderr.puts "extracting #{repo} from #{source_url}"
56
+ $stderr.puts "into #{dir}"
57
+ unpack_zip_here(zip) do |name|
58
+ $stderr.puts " -> #{name}"
59
+ end
60
+ end
61
+
62
+ true
63
+ end
64
+ end
65
+
66
+ class WindowsSetup < Setup
67
+ def setup!
68
+ clear_dir(Ramekin.config.amk_dir, force: @force) or return false
69
+
70
+ Dir.chdir Ramekin.config.amk_dir do
71
+ amk_zip = URI.open('https://dl.smwcentral.net/37906/AddmusicK%201.0.11.zip').read
72
+ unpack_zip_here(amk_zip)
73
+ end
74
+ end
75
+ end
76
+
77
+ class NormalSetup < Setup
78
+ def setup!
79
+ setup_asar!
80
+ setup_amk!
81
+ end
82
+
83
+ def setup_asar!
84
+ unpack_repo_source!('RPGHacker/asar', Ramekin.config.asar_dir) or return
85
+
86
+ Dir.chdir(Ramekin.config.asar_dir) do
87
+ system(cmake, 'src')
88
+ error! "failed to configure asar" unless $?.success?
89
+ system(make)
90
+ error! "failed to compile asar" unless $?.success?
91
+
92
+ lib_file = Dir.glob('asar/lib/*').find do |entry|
93
+ next false unless File.file?(entry)
94
+ next false if File.symlink?(entry)
95
+ entry.end_with?('.dylib') || entry.end_with?('.so') || entry.end_with?('.dll')
96
+ end
97
+
98
+ @asar_lib_file = File.expand_path(lib_file, Ramekin.config.asar_dir)
99
+ end
100
+ end
101
+
102
+ # Using AddMusicKFF as it is the only one that seems to compile cleanly
103
+ # outside of Windows.
104
+ def setup_amk!
105
+ unpack_repo_source!('KungFuFurby/AddMusicKFF', Ramekin.config.amk_dir) or return
106
+
107
+ Dir.chdir(Ramekin.config.amk_dir) do
108
+ system(make)
109
+
110
+ # link in the silly asar lib file
111
+ FileUtils.ln_s(@asar_lib_file, '.')
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
@@ -0,0 +1,40 @@
1
+ module Ramekin
2
+ class ChannelSeparator
3
+ def self.parse(stream)
4
+ new.tap { |x| x.parse(stream) }
5
+ end
6
+
7
+ attr_reader :preamble, :channels, :meta
8
+ def initialize
9
+ @preamble = []
10
+ @channels = []
11
+
12
+ @current = @preamble
13
+ end
14
+
15
+ def preamble?
16
+ @current.equal?(@preamble)
17
+ end
18
+
19
+ def parse(stream)
20
+ stream.each do |el|
21
+ if Token === el && el.type == :channel
22
+ @meta = Meta.new(@preamble.dup).tap(&:parse) if preamble?
23
+ @meta.parse
24
+
25
+ @current = (@channels[el.value.to_i] ||= [])
26
+ end
27
+
28
+ next (@current << el) if preamble?
29
+
30
+ if el.type == :instrument && el.value !~ /\A\d+\z/
31
+ el.meta[:inst] = @meta.instruments.find do |inst|
32
+ inst.name.value == el.value
33
+ end
34
+ end
35
+
36
+ @current << el
37
+ end
38
+ end
39
+ end
40
+ end