gme 0.0.13-x86-linux → 0.1.0-x86-linux
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.
- data/README.rdoc +31 -10
- data/VERSION +1 -1
- data/ext/gme/build/Makefile +2 -2
- data/ext/gme/build/gme.o +0 -0
- data/ext/gme/build/gme_ext.so +0 -0
- data/ext/gme/build/gme_funcs.o +0 -0
- data/ext/gme/build/gme_helpers.o +0 -0
- data/ext/gme/build/util.o +0 -0
- data/ext/gme/gme.c +7 -2
- data/ext/gme/gme_funcs.c +174 -72
- data/ext/gme/gme_funcs.h +3 -0
- data/ext/gme/gme_helpers.c +59 -0
- data/ext/gme/gme_helpers.h +17 -0
- data/lib/gme_ext.so +0 -0
- data/spec/emulator_spec.rb +23 -17
- metadata +7 -4
data/README.rdoc
CHANGED
@@ -1,25 +1,46 @@
|
|
1
|
-
= GME: Game Music
|
1
|
+
= GME: Game Music Emu for Ruby
|
2
2
|
|
3
|
-
This gem allows the use of the gme library
|
4
|
-
by Blargg
|
3
|
+
This gem allows the use of the {gme library}[http://code.google.com/p/game-music-emu]
|
4
|
+
by {Blargg}[http://www.fly.net/~ant/libs/audio.html] in Ruby programs.
|
5
5
|
|
6
|
-
|
6
|
+
Game Music Emu is a collection of video game music file emulators that support various formats and systems.
|
7
|
+
|
8
|
+
At the moment, this gem implements just the basic functionality, and it's not suitable for production.
|
9
|
+
|
10
|
+
== Installation
|
11
|
+
Using Rubygems:
|
12
|
+
|
13
|
+
gem install gme
|
7
14
|
|
8
15
|
== Example usage:
|
9
16
|
|
10
|
-
This gem only outputs raw pcm data
|
17
|
+
Note: This gem only outputs raw pcm data (16 bit samples, stereo).
|
11
18
|
|
19
|
+
require 'rubygems'
|
12
20
|
require 'gme'
|
13
21
|
|
14
|
-
song = GME::Emulator.open('/path/to/file.ext', options = {}) # opens a music file and sets up
|
22
|
+
song = GME::Emulator.open('/path/to/file.ext', options = {}) # opens a music file and sets up a GME::Emulator object
|
15
23
|
# configuration options:
|
16
24
|
# :sample_rate - specifies the output sample rate
|
17
25
|
# :buffer_length - specifies the internal buffer length to be used
|
18
26
|
|
19
|
-
|
27
|
+
file = File.new('output.pcm', 'w') # opens a file for writing
|
28
|
+
|
29
|
+
song.start_track(1) # starts the specified track (0 by default)
|
20
30
|
|
21
|
-
song.
|
31
|
+
song.info # returns a hash with some information about the started track
|
22
32
|
|
23
|
-
song.
|
24
|
-
|
33
|
+
song.play(file, :samples => 1024) # writes the specified number of samples to a file
|
34
|
+
|
35
|
+
song.tell # returns the number of milliseconds played
|
36
|
+
# since the beginning of the track
|
37
|
+
|
38
|
+
song.set_fade(2000) # sets the number of milliseconds to start fading
|
39
|
+
# the track since the beginning of the track
|
40
|
+
|
41
|
+
song.play_silence(file, 2000) # writes the specified milliseconds of silence to a file
|
25
42
|
|
43
|
+
song.play_to_file(file) # completely plays the first track to a file
|
44
|
+
|
45
|
+
file.close # closes the ouput file
|
46
|
+
song.close # release the memory allocated for the emulator
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0
|
1
|
+
0.1.0
|
data/ext/gme/build/Makefile
CHANGED
@@ -87,8 +87,8 @@ extout_prefix =
|
|
87
87
|
target_prefix =
|
88
88
|
LOCAL_LIBS =
|
89
89
|
LIBS = $(LIBRUBYARG_SHARED) -lgme -lpthread -lrt -ldl -lcrypt -lm -lc
|
90
|
-
SRCS =
|
91
|
-
OBJS =
|
90
|
+
SRCS = gme.c util.c gme_funcs.c gme_helpers.c
|
91
|
+
OBJS = gme.o util.o gme_funcs.o gme_helpers.o
|
92
92
|
TARGET = gme_ext
|
93
93
|
DLLIB = $(TARGET).so
|
94
94
|
EXTSTATIC =
|
data/ext/gme/build/gme.o
CHANGED
Binary file
|
data/ext/gme/build/gme_ext.so
CHANGED
Binary file
|
data/ext/gme/build/gme_funcs.o
CHANGED
Binary file
|
Binary file
|
data/ext/gme/build/util.o
CHANGED
Binary file
|
data/ext/gme/gme.c
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
#include <ruby.h>
|
2
|
-
#include "gme_funcs.h"
|
3
2
|
#include "util.h"
|
3
|
+
#include "gme_helpers.h"
|
4
|
+
#include "gme_funcs.h"
|
4
5
|
|
5
6
|
// classes and modules representations
|
6
7
|
VALUE mGME;
|
@@ -22,13 +23,14 @@ void Init_gme_ext()
|
|
22
23
|
cEmulator = rb_define_class_under(mGME, "Emulator", rb_cObject);
|
23
24
|
rb_funcall(cEmulator, rb_intern("attr_reader"), 1, ID2SYM(rb_intern("info")));
|
24
25
|
rb_funcall(cEmulator, rb_intern("attr_reader"), 1, ID2SYM(rb_intern("track_count")));
|
26
|
+
rb_funcall(cEmulator, rb_intern("attr_reader"), 1, ID2SYM(rb_intern("sample_rate")));
|
25
27
|
|
26
28
|
// for debugging
|
27
29
|
rb_funcall(cEmulator, rb_intern("attr_reader"), 1, ID2SYM(rb_intern("internal_buffer")));
|
28
30
|
rb_funcall(cEmulator, rb_intern("attr_reader"), 1, ID2SYM(rb_intern("internal_buffer_length")));
|
29
31
|
// ---
|
30
32
|
|
31
|
-
|
33
|
+
// FIXME: open and play should have 1 mandatory parameter and the rest are optional (i.e.: -2 as parameter count)
|
32
34
|
rb_define_singleton_method(cEmulator, "open", gme_ruby_open, -1);
|
33
35
|
rb_define_method(cEmulator, "close", gme_ruby_close, 0);
|
34
36
|
rb_define_method(cEmulator, "start_track", gme_ruby_start_track, -1);
|
@@ -38,4 +40,7 @@ void Init_gme_ext()
|
|
38
40
|
rb_define_method(cEmulator, "tell", gme_ruby_tell, 0);
|
39
41
|
rb_define_method(cEmulator, "track_ended?", gme_ruby_track_ended, 0);
|
40
42
|
rb_define_method(cEmulator, "ignore_silence", gme_ruby_ignore_silence, 1);
|
43
|
+
rb_define_method(cEmulator, "set_fade", gme_ruby_set_fade, 1);
|
44
|
+
rb_define_method(cEmulator, "play", gme_ruby_play, -1);
|
45
|
+
rb_define_method(cEmulator, "play_silence", gme_ruby_play_silence, 2);
|
41
46
|
}
|
data/ext/gme/gme_funcs.c
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
#include "gme_funcs.h"
|
2
|
+
#include "gme_helpers.h"
|
2
3
|
#include "util.h"
|
3
4
|
|
4
5
|
#include <rubyio.h>
|
@@ -8,19 +9,16 @@ extern VALUE eGenericException;
|
|
8
9
|
extern VALUE eInvalidFile;
|
9
10
|
extern VALUE eTrackNotStarted;
|
10
11
|
|
11
|
-
void gme_ruby_emu_free(void* pointer);
|
12
|
-
|
13
12
|
/*
|
14
|
-
* Opens a new input file
|
15
|
-
* Returns a new instance of GME::Emulator
|
13
|
+
* Opens a new input file.
|
14
|
+
* Returns a new instance of GME::Emulator.
|
15
|
+
* Accepts options in a hash (2nd argument).
|
16
16
|
*/
|
17
17
|
VALUE gme_ruby_open(int argc, VALUE* argv, VALUE self)
|
18
18
|
{
|
19
|
-
Music_Emu*
|
20
|
-
int
|
21
|
-
char*
|
22
|
-
int track = 0; // uses track 0 for getting info (FIXME)
|
23
|
-
gme_info_t* info;
|
19
|
+
Music_Emu* emulator;
|
20
|
+
int c_sample_rate;
|
21
|
+
char* c_path;
|
24
22
|
|
25
23
|
// internal buffer
|
26
24
|
short* buffer;
|
@@ -44,7 +42,7 @@ VALUE gme_ruby_open(int argc, VALUE* argv, VALUE self)
|
|
44
42
|
options = rb_hash_new();
|
45
43
|
}
|
46
44
|
|
47
|
-
// set sample rate
|
45
|
+
// set sample rate from options hash
|
48
46
|
VALUE sample_rate = rb_hash_aref(options, ID2SYM(rb_intern("sample_rate")));
|
49
47
|
if(!NIL_P(sample_rate)) {
|
50
48
|
c_sample_rate = FIX2INT(sample_rate);
|
@@ -54,7 +52,7 @@ VALUE gme_ruby_open(int argc, VALUE* argv, VALUE self)
|
|
54
52
|
c_sample_rate = 44100;
|
55
53
|
}
|
56
54
|
|
57
|
-
// set buffer length
|
55
|
+
// set buffer length from options hash
|
58
56
|
VALUE buffer_len = rb_hash_aref(options, ID2SYM(rb_intern("buffer_length")));
|
59
57
|
if(!NIL_P(buffer_len)) {
|
60
58
|
buffer_length = FIX2INT(buffer_len);
|
@@ -66,33 +64,18 @@ VALUE gme_ruby_open(int argc, VALUE* argv, VALUE self)
|
|
66
64
|
|
67
65
|
// opens the specified file
|
68
66
|
handle_error(gme_open_file(c_path, &emulator, c_sample_rate), eInvalidFile);
|
69
|
-
// and gets the info on the track
|
70
|
-
handle_error(gme_track_info(emulator, &info, track), eGenericException);
|
71
67
|
|
72
68
|
// creates a new instance of GME::Emulator, as a wrapper around Music_Emu
|
73
69
|
VALUE new_instance = Data_Wrap_Struct(cEmulator, 0, gme_ruby_emu_free, emulator);
|
74
70
|
|
75
71
|
// allocates memory for the internal buffer
|
76
|
-
buffer =
|
77
|
-
// and saves a reference for later use (
|
72
|
+
buffer = (short*) malloc(sizeof(short) * buffer_length);
|
73
|
+
// and saves a reference for later use (HACK?)
|
78
74
|
rb_iv_set(new_instance, "@internal_buffer", LONG2NUM((long)buffer));
|
79
75
|
rb_iv_set(new_instance, "@internal_buffer_length", INT2NUM(buffer_length));
|
80
76
|
|
81
|
-
//
|
82
|
-
|
83
|
-
rb_hash_aset(info_hash, ID2SYM(rb_intern("play_length")), INT2FIX(info->play_length));
|
84
|
-
rb_hash_aset(info_hash, ID2SYM(rb_intern("length")), INT2FIX(info->length));
|
85
|
-
rb_hash_aset(info_hash, ID2SYM(rb_intern("intro_length")), INT2FIX(info->intro_length));
|
86
|
-
rb_hash_aset(info_hash, ID2SYM(rb_intern("loop_length")), INT2FIX(info->loop_length));
|
87
|
-
rb_hash_aset(info_hash, ID2SYM(rb_intern("system")), rb_str_new2(info->system));
|
88
|
-
rb_hash_aset(info_hash, ID2SYM(rb_intern("game")), rb_str_new2(info->game));
|
89
|
-
rb_hash_aset(info_hash, ID2SYM(rb_intern("song")), rb_str_new2(info->song));
|
90
|
-
rb_hash_aset(info_hash, ID2SYM(rb_intern("author")), rb_str_new2(info->author));
|
91
|
-
rb_hash_aset(info_hash, ID2SYM(rb_intern("copyright")), rb_str_new2(info->copyright));
|
92
|
-
rb_hash_aset(info_hash, ID2SYM(rb_intern("comment")), rb_str_new2(info->comment));
|
93
|
-
rb_hash_aset(info_hash, ID2SYM(rb_intern("dumper")), rb_str_new2(info->dumper));
|
94
|
-
rb_iv_set(new_instance, "@info", info_hash);
|
95
|
-
gme_free_info(info);
|
77
|
+
// saves the sample rate value for future reference
|
78
|
+
rb_iv_set(new_instance, "@sample_rate", INT2FIX(c_sample_rate));
|
96
79
|
|
97
80
|
// sets the track count
|
98
81
|
int track_count = gme_track_count(emulator);
|
@@ -106,21 +89,37 @@ VALUE gme_ruby_open(int argc, VALUE* argv, VALUE self)
|
|
106
89
|
}
|
107
90
|
|
108
91
|
/*
|
109
|
-
*
|
92
|
+
* Releases all the resources allocated in Emulator#open.
|
93
|
+
* The object is unusable after this call.
|
94
|
+
* TODO: mark valid and invalid objects and raise exceptions if appropiate
|
95
|
+
* instead of simply failing or generating a segfault.
|
110
96
|
*/
|
111
97
|
VALUE gme_ruby_close(VALUE self)
|
112
98
|
{
|
113
|
-
|
99
|
+
Music_Emu* emulator;
|
100
|
+
short* c_buffer;
|
101
|
+
|
102
|
+
Data_Get_Struct(self, Music_Emu, emulator);
|
103
|
+
|
104
|
+
// recovers a pointer to the internal buffer
|
105
|
+
c_buffer = (short*) NUM2LONG(rb_iv_get(self, "@internal_buffer"));
|
106
|
+
|
107
|
+
// releases the memory
|
108
|
+
if(c_buffer != NULL) free(c_buffer);
|
109
|
+
|
110
|
+
return Qnil;
|
114
111
|
}
|
115
112
|
|
116
113
|
/*
|
117
|
-
*
|
118
|
-
*
|
114
|
+
* Starts a track.
|
115
|
+
* If a track is not specified, uses track number 0.
|
116
|
+
* Returns the number of the track started.
|
119
117
|
*/
|
120
118
|
VALUE gme_ruby_start_track(int argc, VALUE* argv, VALUE self)
|
121
119
|
{
|
122
|
-
Music_Emu*
|
123
|
-
int
|
120
|
+
Music_Emu* emulator;
|
121
|
+
int c_track;
|
122
|
+
gme_info_t* info;
|
124
123
|
|
125
124
|
Data_Get_Struct(self, Music_Emu, emulator);
|
126
125
|
|
@@ -133,6 +132,25 @@ VALUE gme_ruby_start_track(int argc, VALUE* argv, VALUE self)
|
|
133
132
|
c_track = 0;
|
134
133
|
}
|
135
134
|
|
135
|
+
// gets the info on the track
|
136
|
+
handle_error(gme_track_info(emulator, &info, c_track), eGenericException);
|
137
|
+
|
138
|
+
// Fills the info hash
|
139
|
+
VALUE info_hash = rb_hash_new();
|
140
|
+
rb_hash_aset(info_hash, ID2SYM(rb_intern("play_length")), INT2FIX(info->play_length));
|
141
|
+
rb_hash_aset(info_hash, ID2SYM(rb_intern("length")), INT2FIX(info->length));
|
142
|
+
rb_hash_aset(info_hash, ID2SYM(rb_intern("intro_length")), INT2FIX(info->intro_length));
|
143
|
+
rb_hash_aset(info_hash, ID2SYM(rb_intern("loop_length")), INT2FIX(info->loop_length));
|
144
|
+
rb_hash_aset(info_hash, ID2SYM(rb_intern("system")), rb_str_new2(info->system));
|
145
|
+
rb_hash_aset(info_hash, ID2SYM(rb_intern("game")), rb_str_new2(info->game));
|
146
|
+
rb_hash_aset(info_hash, ID2SYM(rb_intern("song")), rb_str_new2(info->song));
|
147
|
+
rb_hash_aset(info_hash, ID2SYM(rb_intern("author")), rb_str_new2(info->author));
|
148
|
+
rb_hash_aset(info_hash, ID2SYM(rb_intern("copyright")), rb_str_new2(info->copyright));
|
149
|
+
rb_hash_aset(info_hash, ID2SYM(rb_intern("comment")), rb_str_new2(info->comment));
|
150
|
+
rb_hash_aset(info_hash, ID2SYM(rb_intern("dumper")), rb_str_new2(info->dumper));
|
151
|
+
rb_iv_set(self, "@info", info_hash);
|
152
|
+
gme_free_info(info);
|
153
|
+
|
136
154
|
// starts the track
|
137
155
|
handle_error(gme_start_track(emulator, c_track), eGenericException);
|
138
156
|
|
@@ -153,14 +171,11 @@ VALUE gme_ruby_get_samples(VALUE self)
|
|
153
171
|
short* c_buffer;
|
154
172
|
int c_buffer_len;
|
155
173
|
|
156
|
-
|
157
|
-
if(!RTEST(track_started)) rb_raise(eTrackNotStarted, "you must start a track first");
|
174
|
+
raise_if_track_has_not_started(self);
|
158
175
|
|
159
176
|
Data_Get_Struct(self, Music_Emu, emulator);
|
160
177
|
|
161
|
-
|
162
|
-
c_buffer = (short*) NUM2LONG(rb_iv_get(self, "@internal_buffer"));
|
163
|
-
c_buffer_len = NUM2INT(rb_iv_get(self, "@internal_buffer_length"));
|
178
|
+
get_internal_buffer(self, &c_buffer, &c_buffer_len);
|
164
179
|
|
165
180
|
// plays the file, returning the specified number of samples
|
166
181
|
handle_error(gme_play(emulator, c_buffer_len, c_buffer), eGenericException);
|
@@ -173,8 +188,8 @@ VALUE gme_ruby_get_samples(VALUE self)
|
|
173
188
|
}
|
174
189
|
|
175
190
|
/*
|
176
|
-
* Plays the track 0 of the input file
|
177
|
-
* and writes in the specified (
|
191
|
+
* Plays the track 0 of the input file,
|
192
|
+
* and writes in the specified (Ruby) output file.
|
178
193
|
*/
|
179
194
|
VALUE gme_ruby_play_to_file(VALUE self, VALUE file)
|
180
195
|
{
|
@@ -182,32 +197,22 @@ VALUE gme_ruby_play_to_file(VALUE self, VALUE file)
|
|
182
197
|
short* buffer;
|
183
198
|
FILE* stdio_file;
|
184
199
|
Music_Emu* emulator;
|
185
|
-
|
200
|
+
|
201
|
+
// plays track 0
|
202
|
+
// TODO: receive the track to play as an argument
|
203
|
+
int track = 0;
|
186
204
|
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
rb_raise(eGenericException, "the file is not valid.");
|
191
|
-
}
|
205
|
+
raise_if_invalid_file(file);
|
206
|
+
|
207
|
+
stdio_file = get_stdio_pointer(file);
|
192
208
|
|
193
209
|
// allocates memory for the buffer
|
194
210
|
buffer = (short*) malloc(buffer_size * sizeof(short));
|
195
211
|
|
196
212
|
Data_Get_Struct(self, Music_Emu, emulator);
|
197
213
|
|
198
|
-
//
|
199
|
-
|
200
|
-
|
201
|
-
// if the stdio pointer couldn't be accesed, exit the program
|
202
|
-
if(stdio_file == NULL) {
|
203
|
-
rb_fatal("Couldn't access stdio FILE pointer");
|
204
|
-
}
|
205
|
-
|
206
|
-
// starts track 0
|
207
|
-
handle_error(gme_start_track(emulator, track), eGenericException);
|
208
|
-
|
209
|
-
// track 0 has been started
|
210
|
-
rb_iv_set(self, "@track_started", Qtrue);
|
214
|
+
// starts track
|
215
|
+
rb_funcall(self, rb_intern("start_track"), 1, INT2FIX(track));
|
211
216
|
|
212
217
|
// gets the play length of the track from the info hash
|
213
218
|
VALUE info_hash = rb_iv_get(self, "@info");
|
@@ -240,7 +245,7 @@ VALUE gme_ruby_track_started(VALUE self)
|
|
240
245
|
}
|
241
246
|
|
242
247
|
/*
|
243
|
-
* Returns the number of milliseconds played since the start of the track
|
248
|
+
* Returns the number of milliseconds played since the start of the track.
|
244
249
|
*/
|
245
250
|
VALUE gme_ruby_tell(VALUE self)
|
246
251
|
{
|
@@ -255,7 +260,6 @@ VALUE gme_ruby_tell(VALUE self)
|
|
255
260
|
return INT2FIX(milliseconds);
|
256
261
|
}
|
257
262
|
|
258
|
-
|
259
263
|
/*
|
260
264
|
* Returns true if the track has ended
|
261
265
|
* and false in other cases
|
@@ -264,9 +268,7 @@ VALUE gme_ruby_track_ended(VALUE self)
|
|
264
268
|
{
|
265
269
|
Music_Emu* emulator;
|
266
270
|
|
267
|
-
|
268
|
-
VALUE track_started = gme_ruby_track_started(self);
|
269
|
-
if(!RTEST(track_started)) rb_raise(eTrackNotStarted, "you have to start a track first");
|
271
|
+
raise_if_track_has_not_started(self);
|
270
272
|
|
271
273
|
Data_Get_Struct(self, Music_Emu, emulator);
|
272
274
|
|
@@ -278,8 +280,8 @@ VALUE gme_ruby_track_ended(VALUE self)
|
|
278
280
|
}
|
279
281
|
|
280
282
|
/*
|
281
|
-
*
|
282
|
-
* and skipping at the beginning
|
283
|
+
* Sets whether or not to disable automatic end of track detection
|
284
|
+
* and skipping at the beginning.
|
283
285
|
*/
|
284
286
|
VALUE gme_ruby_ignore_silence(VALUE self, VALUE ignore)
|
285
287
|
{
|
@@ -296,9 +298,109 @@ VALUE gme_ruby_ignore_silence(VALUE self, VALUE ignore)
|
|
296
298
|
}
|
297
299
|
|
298
300
|
/*
|
299
|
-
*
|
301
|
+
* Sets the time in milliseconds to start fading the track.
|
300
302
|
*/
|
301
|
-
|
303
|
+
VALUE gme_ruby_set_fade(VALUE self, VALUE milliseconds)
|
302
304
|
{
|
303
|
-
|
305
|
+
Music_Emu* emulator;
|
306
|
+
|
307
|
+
Data_Get_Struct(self, Music_Emu, emulator);
|
308
|
+
|
309
|
+
gme_set_fade(emulator, FIX2INT(milliseconds));
|
310
|
+
|
311
|
+
return Qnil;
|
312
|
+
}
|
313
|
+
|
314
|
+
/*
|
315
|
+
* Plays the started track to the specified file.
|
316
|
+
* Optionally, one can indicate the number of samples to be played
|
317
|
+
* (given that the buffer allocated previuosly is long enough).
|
318
|
+
*/
|
319
|
+
VALUE gme_ruby_play(int argc, VALUE* argv, VALUE self)
|
320
|
+
{
|
321
|
+
Music_Emu* emulator;
|
322
|
+
int c_number_of_samples;
|
323
|
+
VALUE options; // options hash
|
324
|
+
VALUE file;
|
325
|
+
FILE* stdio_file;
|
326
|
+
short* c_buffer;
|
327
|
+
int c_buffer_len;
|
328
|
+
|
329
|
+
Data_Get_Struct(self, Music_Emu, emulator);
|
330
|
+
|
331
|
+
// file as the first argument
|
332
|
+
file = argv[0];
|
333
|
+
|
334
|
+
raise_if_invalid_file(file);
|
335
|
+
|
336
|
+
stdio_file = get_stdio_pointer(file);
|
337
|
+
|
338
|
+
raise_if_track_has_not_started(self);
|
339
|
+
|
340
|
+
// use the second argument, if present, as the options hash
|
341
|
+
VALUE temp;
|
342
|
+
if(argc >= 2){
|
343
|
+
temp = rb_check_convert_type(argv[1], T_HASH, "Hash", "to_hash");
|
344
|
+
if(!NIL_P(temp)) options = temp;
|
345
|
+
else options = rb_hash_new();
|
346
|
+
}
|
347
|
+
else {
|
348
|
+
options = rb_hash_new();
|
349
|
+
}
|
350
|
+
|
351
|
+
get_internal_buffer(self, &c_buffer, &c_buffer_len);
|
352
|
+
|
353
|
+
// determine the maximum number of samples to play given the buffer size
|
354
|
+
// (recall that buffer was allocated as an array of short)
|
355
|
+
int max_samples = c_buffer_len;
|
356
|
+
|
357
|
+
// sets the number of samples to play
|
358
|
+
VALUE samples = rb_hash_aref(options, ID2SYM(rb_intern("samples")));
|
359
|
+
if(!NIL_P(samples) && FIX2INT(samples) > 0 && FIX2INT(samples) <= max_samples) {
|
360
|
+
c_number_of_samples = FIX2INT(samples);
|
361
|
+
}
|
362
|
+
else {
|
363
|
+
// default, the maximum number of samples permitted by the allocated buffer
|
364
|
+
c_number_of_samples = max_samples;
|
365
|
+
}
|
366
|
+
|
367
|
+
// plays the file, getting the specified number of samples
|
368
|
+
handle_error(gme_play(emulator, c_number_of_samples, c_buffer), eGenericException);
|
369
|
+
|
370
|
+
// writes the samples to the file
|
371
|
+
write_samples(stdio_file, c_number_of_samples, c_buffer);
|
372
|
+
fflush(stdio_file);
|
373
|
+
|
374
|
+
// returns the number of samples
|
375
|
+
return INT2FIX(c_number_of_samples);
|
376
|
+
}
|
377
|
+
|
378
|
+
/*
|
379
|
+
* Inserts the specified milliseconds of silence in a file.
|
380
|
+
*/
|
381
|
+
VALUE gme_ruby_play_silence(VALUE self, VALUE file, VALUE milliseconds)
|
382
|
+
{
|
383
|
+
Music_Emu* emulator;
|
384
|
+
FILE* stdio_file;
|
385
|
+
int samples_to_write;
|
386
|
+
|
387
|
+
Data_Get_Struct(self, Music_Emu, emulator);
|
388
|
+
|
389
|
+
raise_if_invalid_file(file);
|
390
|
+
|
391
|
+
stdio_file = get_stdio_pointer(file);
|
392
|
+
|
393
|
+
// gets the original sample rate specified for the emulator
|
394
|
+
int sample_rate = FIX2INT(rb_iv_get(self, "@sample_rate"));
|
395
|
+
samples_to_write = sample_rate * (FIX2INT(milliseconds) / 1000);
|
396
|
+
|
397
|
+
// writes a number of 0's as silence
|
398
|
+
// (4 in the next calculation because samples are 2 bytes and there are 2 channels)
|
399
|
+
int i;
|
400
|
+
for(i=0; i <(samples_to_write * 4); i++) {
|
401
|
+
fputc(0, stdio_file);
|
402
|
+
}
|
403
|
+
fflush(stdio_file);
|
404
|
+
|
405
|
+
return Qnil;
|
304
406
|
}
|
data/ext/gme/gme_funcs.h
CHANGED
@@ -13,5 +13,8 @@ VALUE gme_ruby_track_started(VALUE self);
|
|
13
13
|
VALUE gme_ruby_tell(VALUE self);
|
14
14
|
VALUE gme_ruby_track_ended(VALUE self);
|
15
15
|
VALUE gme_ruby_ignore_silence(VALUE self, VALUE ignore);
|
16
|
+
VALUE gme_ruby_set_fade(VALUE self, VALUE milliseconds);
|
17
|
+
VALUE gme_ruby_play(int argc, VALUE* argv, VALUE self);
|
18
|
+
VALUE gme_ruby_play_silence(VALUE self, VALUE file, VALUE milliseconds);
|
16
19
|
|
17
20
|
#endif
|
@@ -0,0 +1,59 @@
|
|
1
|
+
#include "gme_helpers.h"
|
2
|
+
|
3
|
+
/*
|
4
|
+
* free function to the GME::Emulator wrapper for Music_Emu
|
5
|
+
*/
|
6
|
+
void gme_ruby_emu_free(void* pointer)
|
7
|
+
{
|
8
|
+
if(pointer != NULL) gme_delete(pointer);
|
9
|
+
}
|
10
|
+
|
11
|
+
/*
|
12
|
+
* Raises an exception if a track has not been started in the emulator.
|
13
|
+
*/
|
14
|
+
void raise_if_track_has_not_started(VALUE emulator)
|
15
|
+
{
|
16
|
+
VALUE track_started = rb_iv_get(emulator, "@track_started");
|
17
|
+
if(!RTEST(track_started)) rb_raise(eTrackNotStarted, "you must start a track first");
|
18
|
+
}
|
19
|
+
|
20
|
+
/*
|
21
|
+
* Raises an exception the specified file is invalid.
|
22
|
+
* i.e. doesn't satisfy the required conditions.
|
23
|
+
*/
|
24
|
+
void raise_if_invalid_file(VALUE file)
|
25
|
+
{
|
26
|
+
// FIXME: currently it *requires* an object of class File
|
27
|
+
if(NIL_P(file) || TYPE(file) != T_FILE) {
|
28
|
+
rb_raise(eGenericException, "the file is not valid.");
|
29
|
+
}
|
30
|
+
|
31
|
+
FILE* stdio_file = get_stdio_pointer(file);
|
32
|
+
|
33
|
+
// raises an exception if the stdio pointer couldn't be accesed
|
34
|
+
if(stdio_file == NULL) {
|
35
|
+
rb_raise(eGenericException, "couldn't access stdio FILE pointer of the specified file");
|
36
|
+
}
|
37
|
+
}
|
38
|
+
|
39
|
+
/*
|
40
|
+
* Recovers a pointer to the internal buffer of the emulator.
|
41
|
+
*/
|
42
|
+
void get_internal_buffer(VALUE emulator, short** buffer, int* buffer_len)
|
43
|
+
{
|
44
|
+
*buffer = (short*) NUM2LONG(rb_iv_get(emulator, "@internal_buffer"));
|
45
|
+
*buffer_len = NUM2INT(rb_iv_get(emulator, "@internal_buffer_length"));
|
46
|
+
}
|
47
|
+
|
48
|
+
/*
|
49
|
+
* Gets the stdio pointer of the specified file.
|
50
|
+
*/
|
51
|
+
FILE* get_stdio_pointer(VALUE file)
|
52
|
+
{
|
53
|
+
FILE* stdio_pointer = NULL;
|
54
|
+
|
55
|
+
// TODO: fix for ruby-1.9 (fptr->stdio_file)
|
56
|
+
stdio_pointer = RFILE(file)->fptr->f;
|
57
|
+
|
58
|
+
return stdio_pointer;
|
59
|
+
}
|
@@ -0,0 +1,17 @@
|
|
1
|
+
#ifndef _GME_HELPERS_H
|
2
|
+
#define _GME_HELPERS_H
|
3
|
+
|
4
|
+
#include <ruby.h>
|
5
|
+
#include <rubyio.h>
|
6
|
+
|
7
|
+
extern VALUE eTrackNotStarted;
|
8
|
+
extern VALUE eGenericException;
|
9
|
+
|
10
|
+
void gme_ruby_emu_free(void* pointer);
|
11
|
+
|
12
|
+
void raise_if_track_has_not_started(VALUE emulator);
|
13
|
+
void raise_if_invalid_file(VALUE file);
|
14
|
+
void get_internal_buffer(VALUE emulator, short** buffer, int* buffer_len);
|
15
|
+
FILE* get_stdio_pointer(VALUE file);
|
16
|
+
|
17
|
+
#endif
|
data/lib/gme_ext.so
CHANGED
Binary file
|
data/spec/emulator_spec.rb
CHANGED
@@ -18,21 +18,8 @@ describe Emulator, "when first created" do
|
|
18
18
|
@song.track_count.should == 1
|
19
19
|
end
|
20
20
|
|
21
|
-
it "should
|
22
|
-
@song.info.
|
23
|
-
end
|
24
|
-
|
25
|
-
it "should correctly return the metadata of track 0 in a hash" do
|
26
|
-
@song.info[:game].should == "Super Castlevania 4"
|
27
|
-
@song.info[:song].should == "Stage Clear"
|
28
|
-
@song.info[:length].should == 4000
|
29
|
-
@song.info[:copyright].should == "1991 Konami"
|
30
|
-
@song.info[:author].should == "Masanori Adachi, Taro Kudou"
|
31
|
-
@song.info[:play_length].should == 4000
|
32
|
-
@song.info[:comment].should == ""
|
33
|
-
@song.info[:dumper].should == "Datschge"
|
34
|
-
@song.info[:system].should == "Super Nintendo"
|
35
|
-
@song.info[:loop_length].should == -1
|
21
|
+
it "should return nil when asked for info" do
|
22
|
+
@song.info.should be_nil
|
36
23
|
end
|
37
24
|
|
38
25
|
it "should indicate that no track has been started" do
|
@@ -77,7 +64,7 @@ describe Emulator, "when first created" do
|
|
77
64
|
lambda { @song.play_to_file(@file) }.should_not raise_exception
|
78
65
|
@song.close
|
79
66
|
File.size("temp.out").should == 706560
|
80
|
-
|
67
|
+
# TODO: check correctness of the generated file
|
81
68
|
end
|
82
69
|
|
83
70
|
after(:each) do
|
@@ -120,7 +107,26 @@ describe Emulator, "when first created" do
|
|
120
107
|
@song.tell.should == 0
|
121
108
|
end
|
122
109
|
|
123
|
-
|
110
|
+
it "should not return nil when asked for the info" do
|
111
|
+
@song.info.should_not be_nil
|
112
|
+
end
|
124
113
|
|
114
|
+
it "should correctly return the metadata of the started track in a hash" do
|
115
|
+
@song.info[:game].should == "Super Castlevania 4"
|
116
|
+
@song.info[:song].should == "Stage Clear"
|
117
|
+
@song.info[:length].should == 4000
|
118
|
+
@song.info[:copyright].should == "1991 Konami"
|
119
|
+
@song.info[:author].should == "Masanori Adachi, Taro Kudou"
|
120
|
+
@song.info[:play_length].should == 4000
|
121
|
+
@song.info[:comment].should == ""
|
122
|
+
@song.info[:dumper].should == "Datschge"
|
123
|
+
@song.info[:system].should == "Super Nintendo"
|
124
|
+
@song.info[:loop_length].should == -1
|
125
|
+
end
|
126
|
+
|
127
|
+
# TODO: complete examples for the methods:
|
128
|
+
# get_samples, set_fade, play_silence, play, close, tell, ignore_silence
|
129
|
+
# TODO: add examples for the open method with options
|
130
|
+
# :sample_rate, :buffer_length
|
125
131
|
end
|
126
132
|
end
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
+
- 1
|
7
8
|
- 0
|
8
|
-
|
9
|
-
version: 0.0.13
|
9
|
+
version: 0.1.0
|
10
10
|
platform: x86-linux
|
11
11
|
authors:
|
12
12
|
- "Carlos Beltr\xC3\xA1n-Recabarren"
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-
|
17
|
+
date: 2010-05-14 00:00:00 -04:00
|
18
18
|
default_executable:
|
19
19
|
dependencies: []
|
20
20
|
|
@@ -36,12 +36,15 @@ files:
|
|
36
36
|
- ext/gme/build/gme.o
|
37
37
|
- ext/gme/build/gme_ext.so
|
38
38
|
- ext/gme/build/gme_funcs.o
|
39
|
+
- ext/gme/build/gme_helpers.o
|
39
40
|
- ext/gme/build/mkmf.log
|
40
41
|
- ext/gme/build/util.o
|
41
42
|
- ext/gme/extconf.rb
|
42
43
|
- ext/gme/gme.c
|
43
44
|
- ext/gme/gme_funcs.c
|
44
45
|
- ext/gme/gme_funcs.h
|
46
|
+
- ext/gme/gme_helpers.c
|
47
|
+
- ext/gme/gme_helpers.h
|
45
48
|
- ext/gme/util.c
|
46
49
|
- ext/gme/util.h
|
47
50
|
- lib/gme.rb
|
@@ -79,5 +82,5 @@ signing_key:
|
|
79
82
|
specification_version: 3
|
80
83
|
summary: gme for Ruby
|
81
84
|
test_files:
|
82
|
-
- spec/emulator_spec.rb
|
83
85
|
- spec/spec_helper.rb
|
86
|
+
- spec/emulator_spec.rb
|