gme 0.0.13-x86-linux → 0.1.0-x86-linux
Sign up to get free protection for your applications and to get access to all the features.
- 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
|