music_player 0.9.0-universal-darwin-9
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/LICENSE +22 -0
- data/Rakefile +36 -0
- data/examples/drum_machine.rb +64 -0
- data/ext/music_player/extconf.rb +9 -0
- data/ext/music_player/music_player.c +1440 -0
- data/ext/music_player/util.h +25 -0
- data/lib/music_player.rb +216 -0
- data/test/example.mid +0 -0
- data/test/extended_tempo_event_test.rb +15 -0
- data/test/midi_channel_message_test.rb +93 -0
- data/test/midi_note_message_test.rb +50 -0
- data/test/music_event_iterator_test.rb +160 -0
- data/test/music_player_test.rb +40 -0
- data/test/music_sequence_test.rb +52 -0
- data/test/music_track_collection_test.rb +53 -0
- data/test/music_track_test.rb +92 -0
- data/test/test_helper.rb +4 -0
- metadata +77 -0
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2009 Jeremy Voorhis <jvoorhis@gmail.com>
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person
|
4
|
+
obtaining a copy of this software and associated documentation
|
5
|
+
files (the "Software"), to deal in the Software without
|
6
|
+
restriction, including without limitation the rights to use,
|
7
|
+
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
8
|
+
copies of the Software, and to permit persons to whom the
|
9
|
+
Software is furnished to do so, subject to the following
|
10
|
+
conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
17
|
+
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
19
|
+
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
20
|
+
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
21
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/gempackagetask'
|
4
|
+
require 'rbconfig'
|
5
|
+
|
6
|
+
def rb_cmd
|
7
|
+
@rb_cmd ||= File.join(Config::CONFIG['bindir'],
|
8
|
+
Config::CONFIG['ruby_install_name']
|
9
|
+
).sub(/.*\s.*/m, '"\&"')
|
10
|
+
end
|
11
|
+
|
12
|
+
task :build do
|
13
|
+
Dir.chdir('ext') do
|
14
|
+
system(rb_cmd, 'music_player/extconf.rb')
|
15
|
+
system('make')
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
task :clean do
|
20
|
+
Dir['ext/*{Makefile,.o,.bundle}'].each do |path|
|
21
|
+
FileUtils.rm_rf(path)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
Rake::TestTask.new do |t|
|
26
|
+
t.libs << 'ext'
|
27
|
+
t.test_files = FileList['test/*_test.rb']
|
28
|
+
t.verbose = true
|
29
|
+
end
|
30
|
+
|
31
|
+
task :test => :build # Always test the latest build.
|
32
|
+
|
33
|
+
spec = eval open('music_player.gemspec').read
|
34
|
+
Rake::GemPackageTask.new spec do |pkg| end
|
35
|
+
|
36
|
+
task :default => :test
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'music_player'
|
2
|
+
|
3
|
+
class DrumMachine
|
4
|
+
include AudioToolbox
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@player = MusicPlayer.new
|
8
|
+
@sequence = MusicSequence.new
|
9
|
+
@track = @sequence.tracks.new
|
10
|
+
@track.add(0.0, MIDIProgramChangeMessage.new(:channel => 10, :program => 26))
|
11
|
+
@track.add(0.0, MIDIControlChangeMessage.new(:channel => 10, :number => 32, :value => 1))
|
12
|
+
# Use the following call sequence to use an alternate midi destination.
|
13
|
+
# Hopefully a more complete interface will be implemented soon. MIDI
|
14
|
+
# destinations are referenced by their index beginning at 0.
|
15
|
+
# See also CoreMIDI::get_number_of_destinations().
|
16
|
+
#
|
17
|
+
# @sequence.midi_endpoint = CoreMIDI.get_destination(ARGV.shift.to_i)
|
18
|
+
@player.sequence = @sequence
|
19
|
+
build_track
|
20
|
+
end
|
21
|
+
|
22
|
+
def drum(beat, note)
|
23
|
+
@track.add(beat,
|
24
|
+
MIDINoteMessage.new(:note => note,
|
25
|
+
:velocity => 80,
|
26
|
+
:channel => 10,
|
27
|
+
:duration => 0.1))
|
28
|
+
end
|
29
|
+
|
30
|
+
def kick1(beat)
|
31
|
+
drum(beat, 35)
|
32
|
+
end
|
33
|
+
|
34
|
+
def kick2(beat)
|
35
|
+
drum(beat, 36)
|
36
|
+
end
|
37
|
+
|
38
|
+
def snare(beat)
|
39
|
+
drum(beat, 40)
|
40
|
+
end
|
41
|
+
|
42
|
+
def build_track
|
43
|
+
0.upto(15) do |beat|
|
44
|
+
kick1(beat) # every downbeat
|
45
|
+
kick2(beat+0.5) # every upbeat
|
46
|
+
if beat % 4 == 0
|
47
|
+
extra = (beat % 8)/4
|
48
|
+
snare(beat+extra)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
@track.length = 16
|
53
|
+
@track.loop_info = { :duration => @track.length, :number => 0 }
|
54
|
+
end
|
55
|
+
|
56
|
+
def run
|
57
|
+
@player.start
|
58
|
+
puts "Press return to exit."
|
59
|
+
gets
|
60
|
+
@player.stop
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
DrumMachine.new.run
|
@@ -0,0 +1,1440 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright (c) 2009 Jeremy Voorhis <jvoorhis@gmail.com>
|
3
|
+
*/
|
4
|
+
|
5
|
+
#include <ruby.h>
|
6
|
+
#include "util.h"
|
7
|
+
#include <AudioToolbox/MusicPlayer.h>
|
8
|
+
#include <CoreMIDI/MIDIServices.h>
|
9
|
+
|
10
|
+
/* Ruby type decls */
|
11
|
+
|
12
|
+
static VALUE rb_mCoreMIDI;
|
13
|
+
|
14
|
+
static VALUE rb_mAudioToolbox;
|
15
|
+
|
16
|
+
static VALUE rb_eTrackNotFound;
|
17
|
+
static VALUE rb_eEndOfTrack;
|
18
|
+
static VALUE rb_eStartOfTrack;
|
19
|
+
static VALUE rb_eNoSequence;
|
20
|
+
static VALUE rb_eIllegalTrackDestination;
|
21
|
+
|
22
|
+
static VALUE rb_cMusicPlayer;
|
23
|
+
static VALUE rb_cMusicSequence;
|
24
|
+
static VALUE rb_cMusicTrack;
|
25
|
+
static VALUE rb_cMusicTrackCollection;
|
26
|
+
static VALUE rb_cMIDINoteMessage;
|
27
|
+
static VALUE rb_cMIDIChannelMessage;
|
28
|
+
static VALUE rb_cMIDIKeyPressureMessage;
|
29
|
+
static VALUE rb_cMIDIControlChangeMessage;
|
30
|
+
static VALUE rb_cMIDIProgramChangeMessage;
|
31
|
+
static VALUE rb_cMIDIChannelPressureMessage;
|
32
|
+
static VALUE rb_cMIDIPitchBendMessage;
|
33
|
+
static VALUE rb_cExtendedTempoEvent;
|
34
|
+
static VALUE rb_cMusicEventIterator;
|
35
|
+
|
36
|
+
/* Ruby symbols */
|
37
|
+
static VALUE rb_sBeat;
|
38
|
+
static VALUE rb_sBpm;
|
39
|
+
static VALUE rb_sChannel;
|
40
|
+
static VALUE rb_sData1;
|
41
|
+
static VALUE rb_sData2;
|
42
|
+
static VALUE rb_sDuration;
|
43
|
+
static VALUE rb_sLength;
|
44
|
+
static VALUE rb_sLoopInfo;
|
45
|
+
static VALUE rb_sMute;
|
46
|
+
static VALUE rb_sNote;
|
47
|
+
static VALUE rb_sNumber;
|
48
|
+
static VALUE rb_sPressure;
|
49
|
+
static VALUE rb_sProgram;
|
50
|
+
static VALUE rb_sReleaseVelocity;
|
51
|
+
static VALUE rb_sSamp;
|
52
|
+
static VALUE rb_sSecs;
|
53
|
+
static VALUE rb_sSolo;
|
54
|
+
static VALUE rb_sStatus;
|
55
|
+
static VALUE rb_sValue;
|
56
|
+
static VALUE rb_sVelocity;
|
57
|
+
|
58
|
+
/* Utils */
|
59
|
+
|
60
|
+
#define RAISE_OSSTATUS(error,what) \
|
61
|
+
if (error == kAudioToolboxErr_TrackIndexError) {\
|
62
|
+
rb_raise(rb_eRangeError, "Index is out of range.");\
|
63
|
+
} else if (error == kAudioToolboxErr_TrackNotFound) {\
|
64
|
+
rb_raise(rb_eTrackNotFound, "Track not found.");\
|
65
|
+
} else if (error == kAudioToolboxErr_EndOfTrack) {\
|
66
|
+
rb_raise(rb_eEndOfTrack, "Reached end of track.");\
|
67
|
+
} else if (error == kAudioToolboxErr_StartOfTrack) {\
|
68
|
+
rb_raise(rb_eStartOfTrack, "Reached start of track.");\
|
69
|
+
} else if (error == kAudioToolboxErr_IllegalTrackDestination) {\
|
70
|
+
rb_raise(rb_eIllegalTrackDestination, "Illegal track destination.");\
|
71
|
+
} else if (error == kAudioToolboxErr_NoSequence) {\
|
72
|
+
rb_raise(rb_eNoSequence, "No sequence was given.");\
|
73
|
+
} else {\
|
74
|
+
rb_raise(rb_eRuntimeError, "%s failed with OSStatus %i.", what, (int)error);\
|
75
|
+
}
|
76
|
+
|
77
|
+
/* CoreMIDI defns */
|
78
|
+
|
79
|
+
static VALUE
|
80
|
+
core_midi_get_number_of_destinations (VALUE mod)
|
81
|
+
{
|
82
|
+
return UINT2NUM(MIDIGetNumberOfDestinations());
|
83
|
+
}
|
84
|
+
|
85
|
+
static VALUE
|
86
|
+
core_midi_get_destination (VALUE mod, VALUE idx)
|
87
|
+
{
|
88
|
+
ItemCount ic = NUM2UINT(idx);
|
89
|
+
MIDIEndpointRef ref = MIDIGetDestination(ic);
|
90
|
+
if (NULL == ref) { return Qnil; }
|
91
|
+
return ULONG2NUM((UInt32) ref);
|
92
|
+
}
|
93
|
+
|
94
|
+
/* MusicPlayer defns */
|
95
|
+
|
96
|
+
static void
|
97
|
+
player_free (MusicPlayer *player)
|
98
|
+
{
|
99
|
+
OSStatus err;
|
100
|
+
if (player) {
|
101
|
+
require_noerr( err = DisposeMusicPlayer(*player), fail );
|
102
|
+
free(player);
|
103
|
+
}
|
104
|
+
return;
|
105
|
+
|
106
|
+
fail:
|
107
|
+
rb_warning("DisposeMusicPlayer() failed with OSStatus %i.", (int) err);
|
108
|
+
}
|
109
|
+
|
110
|
+
static VALUE
|
111
|
+
player_alloc (VALUE class)
|
112
|
+
{
|
113
|
+
MusicPlayer *player;
|
114
|
+
return Data_Make_Struct(rb_cMusicPlayer, MusicPlayer, 0, player_free, player);
|
115
|
+
}
|
116
|
+
|
117
|
+
static VALUE
|
118
|
+
player_init (VALUE self)
|
119
|
+
{
|
120
|
+
MusicPlayer *player;
|
121
|
+
OSStatus err;
|
122
|
+
Data_Get_Struct(self, MusicPlayer, player);
|
123
|
+
require_noerr( err = NewMusicPlayer(player), fail );
|
124
|
+
return self;
|
125
|
+
|
126
|
+
fail:
|
127
|
+
RAISE_OSSTATUS(err, "NewMusicPlayer()");
|
128
|
+
}
|
129
|
+
|
130
|
+
static VALUE
|
131
|
+
player_is_playing (VALUE self)
|
132
|
+
{
|
133
|
+
MusicPlayer *player;
|
134
|
+
Boolean playing;
|
135
|
+
OSStatus err;
|
136
|
+
|
137
|
+
Data_Get_Struct(self, MusicPlayer, player);
|
138
|
+
require_noerr( err = MusicPlayerIsPlaying(*player, &playing), fail );
|
139
|
+
return playing ? Qtrue : Qfalse;
|
140
|
+
|
141
|
+
fail:
|
142
|
+
RAISE_OSSTATUS(err, "MusicPlayerIsPlaying()");
|
143
|
+
}
|
144
|
+
|
145
|
+
static VALUE
|
146
|
+
player_get_sequence (VALUE self)
|
147
|
+
{
|
148
|
+
return rb_iv_get(self, "@sequence");
|
149
|
+
}
|
150
|
+
|
151
|
+
static VALUE
|
152
|
+
player_set_sequence (VALUE self, VALUE rb_seq)
|
153
|
+
{
|
154
|
+
MusicPlayer *player;
|
155
|
+
MusicSequence *seq;
|
156
|
+
OSStatus err;
|
157
|
+
|
158
|
+
Data_Get_Struct(self, MusicPlayer, player);
|
159
|
+
Data_Get_Struct(rb_seq, MusicSequence, seq);
|
160
|
+
rb_iv_set(self, "@sequence", rb_seq);
|
161
|
+
|
162
|
+
require_noerr( err = MusicPlayerSetSequence(*player, *seq), fail );
|
163
|
+
return rb_seq;
|
164
|
+
|
165
|
+
fail:
|
166
|
+
RAISE_OSSTATUS(err, "MusicPlayerSetSequence()");
|
167
|
+
}
|
168
|
+
|
169
|
+
static VALUE
|
170
|
+
player_start (VALUE self)
|
171
|
+
{
|
172
|
+
MusicPlayer *player;
|
173
|
+
OSStatus err;
|
174
|
+
|
175
|
+
Data_Get_Struct(self, MusicPlayer, player);
|
176
|
+
require_noerr( err = MusicPlayerStart(*player), fail );
|
177
|
+
return Qnil;
|
178
|
+
|
179
|
+
fail:
|
180
|
+
RAISE_OSSTATUS(err, "MusicPlayerStart()");
|
181
|
+
}
|
182
|
+
|
183
|
+
static VALUE
|
184
|
+
player_stop (VALUE self)
|
185
|
+
{
|
186
|
+
MusicPlayer *player;
|
187
|
+
OSStatus err;
|
188
|
+
|
189
|
+
Data_Get_Struct(self, MusicPlayer, player);
|
190
|
+
require_noerr( err = MusicPlayerStop(*player), fail );
|
191
|
+
return Qnil;
|
192
|
+
|
193
|
+
fail:
|
194
|
+
RAISE_OSSTATUS(err, "MusicPlayerStop()");
|
195
|
+
}
|
196
|
+
|
197
|
+
static VALUE
|
198
|
+
player_get_time (VALUE self)
|
199
|
+
{
|
200
|
+
MusicPlayer *player;
|
201
|
+
MusicTimeStamp ts;
|
202
|
+
OSStatus err;
|
203
|
+
|
204
|
+
Data_Get_Struct(self, MusicPlayer, player);
|
205
|
+
require_noerr( err = MusicPlayerGetTime(*player, &ts), fail );
|
206
|
+
return rb_float_new((Float64) ts);
|
207
|
+
|
208
|
+
fail:
|
209
|
+
RAISE_OSSTATUS(err, "MusicPlayerGetTime()");
|
210
|
+
}
|
211
|
+
|
212
|
+
static VALUE
|
213
|
+
player_set_time (VALUE self, VALUE rb_ts)
|
214
|
+
{
|
215
|
+
if (!PRIM_NUM_P(rb_ts))
|
216
|
+
rb_raise(rb_eArgError, "Expected argument to be a number.");
|
217
|
+
|
218
|
+
MusicPlayer *player;
|
219
|
+
MusicTimeStamp ts;
|
220
|
+
OSStatus err;
|
221
|
+
|
222
|
+
ts = rb_num2dbl(rb_ts);
|
223
|
+
Data_Get_Struct(self, MusicPlayer, player);
|
224
|
+
require_noerr( err = MusicPlayerSetTime(*player, ts), fail );
|
225
|
+
return Qnil;
|
226
|
+
|
227
|
+
fail:
|
228
|
+
RAISE_OSSTATUS(err, "MusicPlayerSetTime()");
|
229
|
+
}
|
230
|
+
|
231
|
+
static VALUE
|
232
|
+
player_get_play_rate_scalar (VALUE self)
|
233
|
+
{
|
234
|
+
MusicPlayer *player;
|
235
|
+
Float64 scalar;
|
236
|
+
OSStatus err;
|
237
|
+
|
238
|
+
Data_Get_Struct(self, MusicPlayer, player);
|
239
|
+
require_noerr( err = MusicPlayerGetPlayRateScalar(*player, &scalar), fail );
|
240
|
+
return rb_float_new(scalar);
|
241
|
+
|
242
|
+
fail:
|
243
|
+
RAISE_OSSTATUS(err, "MusicPlayerGetPlayRateScalar()");
|
244
|
+
}
|
245
|
+
|
246
|
+
static VALUE
|
247
|
+
player_set_play_rate_scalar (VALUE self, VALUE rb_scalar)
|
248
|
+
{
|
249
|
+
if (!PRIM_NUM_P(rb_scalar))
|
250
|
+
rb_raise(rb_eArgError, "Expected scalar to be a number.");
|
251
|
+
|
252
|
+
MusicPlayer *player;
|
253
|
+
Float64 scalar;
|
254
|
+
OSStatus err;
|
255
|
+
|
256
|
+
scalar = NUM2DBL(rb_scalar);
|
257
|
+
Data_Get_Struct(self, MusicPlayer, player);
|
258
|
+
require_noerr( err = MusicPlayerSetPlayRateScalar(*player, scalar), fail );
|
259
|
+
return Qnil;
|
260
|
+
|
261
|
+
fail:
|
262
|
+
RAISE_OSSTATUS(err, "MusicPlayerSetPlayRateScalar()");
|
263
|
+
}
|
264
|
+
|
265
|
+
static VALUE
|
266
|
+
player_host_time_for_beats (VALUE self, VALUE rb_beats)
|
267
|
+
{
|
268
|
+
MusicTimeStamp beats = NUM2ULONG(rb_beats);
|
269
|
+
|
270
|
+
MusicPlayer *player;
|
271
|
+
Data_Get_Struct(self, MusicPlayer, player);
|
272
|
+
|
273
|
+
UInt64 host_time = 0;
|
274
|
+
OSStatus err;
|
275
|
+
|
276
|
+
require_noerr( err = MusicPlayerGetHostTimeForBeats(*player, beats, &host_time), fail );
|
277
|
+
return rb_float_new(host_time);
|
278
|
+
|
279
|
+
fail:
|
280
|
+
RAISE_OSSTATUS(err, "MusicPlayerGetHostTimeForBeats()");
|
281
|
+
}
|
282
|
+
|
283
|
+
/* Sequence defns */
|
284
|
+
|
285
|
+
static void
|
286
|
+
sequence_free (MusicSequence *seq)
|
287
|
+
{
|
288
|
+
OSStatus err;
|
289
|
+
if (seq) {
|
290
|
+
require_noerr( err = DisposeMusicSequence(*seq), fail );
|
291
|
+
free(seq);
|
292
|
+
}
|
293
|
+
return;
|
294
|
+
|
295
|
+
fail:
|
296
|
+
rb_warning("DisposeMusicSequence() failed with %i.", (int) err);
|
297
|
+
}
|
298
|
+
|
299
|
+
static VALUE
|
300
|
+
sequence_alloc (VALUE class)
|
301
|
+
{
|
302
|
+
MusicSequence *seq;
|
303
|
+
return Data_Make_Struct(rb_cMusicSequence, MusicSequence, 0, sequence_free, seq);
|
304
|
+
}
|
305
|
+
|
306
|
+
static VALUE
|
307
|
+
sequence_init (VALUE self)
|
308
|
+
{
|
309
|
+
MusicSequence *seq;
|
310
|
+
OSStatus err;
|
311
|
+
Data_Get_Struct(self, MusicSequence, seq);
|
312
|
+
require_noerr( err = NewMusicSequence(seq), fail );
|
313
|
+
rb_iv_set(self, "@tracks",
|
314
|
+
rb_funcall(rb_cMusicTrackCollection, rb_intern("new"), 1, self));
|
315
|
+
|
316
|
+
return self;
|
317
|
+
|
318
|
+
fail:
|
319
|
+
RAISE_OSSTATUS(err, "NewMusicSequence()");
|
320
|
+
}
|
321
|
+
|
322
|
+
static VALUE
|
323
|
+
sequence_set_midi_endpoint (VALUE self, VALUE rb_endpoint_ref)
|
324
|
+
{
|
325
|
+
MusicSequence *seq;
|
326
|
+
UInt32 ref = NUM2ULONG(rb_funcall(rb_mKernel, rb_intern("Integer"), 1, rb_endpoint_ref));
|
327
|
+
OSStatus err;
|
328
|
+
|
329
|
+
Data_Get_Struct(self, MusicSequence, seq);
|
330
|
+
require_noerr( err = MusicSequenceSetMIDIEndpoint(*seq, (MIDIEndpointRef) ref), fail);
|
331
|
+
return Qnil;
|
332
|
+
|
333
|
+
fail:
|
334
|
+
RAISE_OSSTATUS(err, "MusicSequenceSetMIDIEndpoint()");
|
335
|
+
}
|
336
|
+
|
337
|
+
static VALUE
|
338
|
+
sequence_get_type (VALUE self)
|
339
|
+
{
|
340
|
+
MusicSequence *seq;
|
341
|
+
MusicSequenceType type;
|
342
|
+
OSStatus err;
|
343
|
+
|
344
|
+
Data_Get_Struct(self, MusicSequence, seq);
|
345
|
+
require_noerr( err = MusicSequenceGetSequenceType(*seq, &type), fail );
|
346
|
+
|
347
|
+
switch (type) {
|
348
|
+
case kMusicSequenceType_Beats:
|
349
|
+
return rb_sBeat;
|
350
|
+
case kMusicSequenceType_Seconds:
|
351
|
+
return rb_sSecs;
|
352
|
+
case kMusicSequenceType_Samples:
|
353
|
+
return rb_sSamp;
|
354
|
+
default:
|
355
|
+
rb_raise(rb_eRuntimeError, "Unrecognized sequence type.");
|
356
|
+
}
|
357
|
+
|
358
|
+
fail:
|
359
|
+
RAISE_OSSTATUS(err, "MusicSequenceGetSequenceType()");
|
360
|
+
}
|
361
|
+
|
362
|
+
static VALUE
|
363
|
+
sequence_set_type (VALUE self, VALUE rb_type)
|
364
|
+
{
|
365
|
+
MusicSequence *seq;
|
366
|
+
MusicSequenceType type;
|
367
|
+
if (rb_type == rb_sBeat)
|
368
|
+
type = kMusicSequenceType_Beats;
|
369
|
+
else if (rb_type == rb_sSecs)
|
370
|
+
type = kMusicSequenceType_Seconds;
|
371
|
+
else if (rb_type == rb_sSamp)
|
372
|
+
type = kMusicSequenceType_Samples;
|
373
|
+
else
|
374
|
+
rb_raise(rb_eArgError, "Expected :type to be one of :beat, :secs, :samp.");
|
375
|
+
|
376
|
+
Data_Get_Struct(self, MusicSequence, seq);
|
377
|
+
OSStatus err;
|
378
|
+
require_noerr( err = MusicSequenceSetSequenceType(*seq, type), fail );
|
379
|
+
return Qnil;
|
380
|
+
|
381
|
+
fail:
|
382
|
+
RAISE_OSSTATUS(err, "MusicSequenceSetSequenceType()");
|
383
|
+
}
|
384
|
+
|
385
|
+
static VALUE
|
386
|
+
sequence_save (VALUE self, VALUE rb_path)
|
387
|
+
{
|
388
|
+
CFURLRef url = PATH2CFURL(rb_funcall(rb_path, rb_intern("to_s"), 0));
|
389
|
+
MusicSequence *seq;
|
390
|
+
OSStatus err;
|
391
|
+
|
392
|
+
Data_Get_Struct(self, MusicSequence, seq);
|
393
|
+
require_noerr( err = MusicSequenceFileCreate(*seq, url, kMusicSequenceFile_MIDIType, kMusicSequenceFileFlags_EraseFile, 0), fail );
|
394
|
+
CFRelease(url);
|
395
|
+
|
396
|
+
return Qnil;
|
397
|
+
|
398
|
+
fail:
|
399
|
+
CFRelease(url);
|
400
|
+
RAISE_OSSTATUS(err, "MusicSequenceFileCreate()");
|
401
|
+
}
|
402
|
+
|
403
|
+
static VALUE
|
404
|
+
sequence_load (VALUE self, VALUE rb_path)
|
405
|
+
{
|
406
|
+
CFURLRef url = PATH2CFURL(StringValue(rb_path));
|
407
|
+
MusicSequence *seq;
|
408
|
+
OSStatus err;
|
409
|
+
|
410
|
+
Data_Get_Struct(self, MusicSequence, seq);
|
411
|
+
require_noerr( err = MusicSequenceFileLoad(*seq, url, kMusicSequenceFile_MIDIType, kMusicSequenceLoadSMF_ChannelsToTracks), fail );
|
412
|
+
CFRelease(url);
|
413
|
+
|
414
|
+
return Qnil;
|
415
|
+
|
416
|
+
fail:
|
417
|
+
CFRelease(url);
|
418
|
+
RAISE_OSSTATUS(err, "MusicSequenceFileLoad()");
|
419
|
+
}
|
420
|
+
|
421
|
+
/* Track defns */
|
422
|
+
|
423
|
+
static void
|
424
|
+
track_free (MusicTrack *track)
|
425
|
+
{
|
426
|
+
if(track) free(track);
|
427
|
+
}
|
428
|
+
|
429
|
+
static VALUE
|
430
|
+
track_init (int argc, VALUE *argv, VALUE self)
|
431
|
+
{
|
432
|
+
VALUE rb_seq, rb_options;
|
433
|
+
rb_scan_args(argc, argv, "11", &rb_seq, &rb_options);
|
434
|
+
|
435
|
+
rb_iv_set(self, "@sequence", rb_seq);
|
436
|
+
|
437
|
+
if (T_HASH == TYPE(rb_options)) {
|
438
|
+
VALUE loop_info = rb_hash_aref(rb_options, rb_sLoopInfo),
|
439
|
+
mute = rb_hash_aref(rb_options, rb_sMute),
|
440
|
+
solo = rb_hash_aref(rb_options, rb_sSolo),
|
441
|
+
length = rb_hash_aref(rb_options, rb_sLength);
|
442
|
+
|
443
|
+
if (!NIL_P(loop_info))
|
444
|
+
rb_funcall(self, rb_intern("loop_info="), 1, loop_info);
|
445
|
+
if (!NIL_P(mute))
|
446
|
+
rb_funcall(self, rb_intern("mute="), 1, mute);
|
447
|
+
if (!NIL_P(solo))
|
448
|
+
rb_funcall(self, rb_intern("solo="), 1, solo);
|
449
|
+
if (!NIL_P(length))
|
450
|
+
rb_funcall(self, rb_intern("length="), 1, length);
|
451
|
+
}
|
452
|
+
|
453
|
+
return self;
|
454
|
+
}
|
455
|
+
|
456
|
+
static VALUE
|
457
|
+
track_internal_new (VALUE rb_seq, MusicTrack *track)
|
458
|
+
{
|
459
|
+
VALUE rb_track, argv[1];
|
460
|
+
rb_track = Data_Wrap_Struct(rb_cMusicTrack, 0, track_free, track);
|
461
|
+
argv[0] = rb_seq;
|
462
|
+
rb_obj_call_init(rb_track, 1, argv);
|
463
|
+
return rb_track;
|
464
|
+
}
|
465
|
+
|
466
|
+
static VALUE
|
467
|
+
track_new (int argc, VALUE *argv, VALUE class)
|
468
|
+
{
|
469
|
+
VALUE rb_seq, rb_options, rb_track, init_argv[2];
|
470
|
+
MusicSequence *seq;
|
471
|
+
MusicTrack *track;
|
472
|
+
OSStatus err;
|
473
|
+
|
474
|
+
rb_scan_args(argc, argv, "11", &rb_seq, &rb_options);
|
475
|
+
Data_Get_Struct(rb_seq, MusicSequence, seq);
|
476
|
+
|
477
|
+
rb_track = Data_Make_Struct(rb_cMusicTrack, MusicTrack, 0, track_free, track);
|
478
|
+
require_noerr( err = MusicSequenceNewTrack(*seq, track), fail );
|
479
|
+
init_argv[0] = rb_seq;
|
480
|
+
init_argv[1] = rb_options;
|
481
|
+
rb_obj_call_init(rb_track, 2, init_argv);
|
482
|
+
return rb_track;
|
483
|
+
|
484
|
+
fail:
|
485
|
+
RAISE_OSSTATUS(err, "MusicSequenceNewTrack()");
|
486
|
+
}
|
487
|
+
|
488
|
+
static VALUE
|
489
|
+
track_add_midi_note_message (VALUE self, VALUE rb_at, VALUE rb_msg)
|
490
|
+
{
|
491
|
+
MusicTrack *track;
|
492
|
+
MIDINoteMessage *msg;
|
493
|
+
MusicTimeStamp ts = (MusicTimeStamp) NUM2DBL(rb_at);
|
494
|
+
OSStatus err;
|
495
|
+
|
496
|
+
Data_Get_Struct(self, MusicTrack, track);
|
497
|
+
Data_Get_Struct(rb_msg, MIDINoteMessage, msg);
|
498
|
+
require_noerr( err = MusicTrackNewMIDINoteEvent(*track, ts, msg), fail );
|
499
|
+
return Qnil;
|
500
|
+
|
501
|
+
fail:
|
502
|
+
RAISE_OSSTATUS(err, "MusicTrackNewMIDINoteEvent()");
|
503
|
+
}
|
504
|
+
|
505
|
+
static VALUE
|
506
|
+
track_add_midi_channel_message (VALUE self, VALUE rb_at, VALUE rb_msg)
|
507
|
+
{
|
508
|
+
MusicTrack *track;
|
509
|
+
MIDIChannelMessage *msg;
|
510
|
+
MusicTimeStamp ts = (MusicTimeStamp) NUM2DBL(rb_at);
|
511
|
+
OSStatus err;
|
512
|
+
|
513
|
+
Data_Get_Struct(self, MusicTrack, track);
|
514
|
+
Data_Get_Struct(rb_msg, MIDIChannelMessage, msg);
|
515
|
+
require_noerr( err = MusicTrackNewMIDIChannelEvent(*track, ts, msg), fail );
|
516
|
+
return Qnil;
|
517
|
+
|
518
|
+
fail:
|
519
|
+
RAISE_OSSTATUS(err, "MusicTrackNewMIDIChannelEvent()");
|
520
|
+
}
|
521
|
+
|
522
|
+
static VALUE
|
523
|
+
track_add_extended_tempo_event (VALUE self, VALUE rb_at, VALUE rb_bpm)
|
524
|
+
{
|
525
|
+
MusicTrack *track;
|
526
|
+
MusicTimeStamp ts;
|
527
|
+
Float64 bpm;
|
528
|
+
OSStatus err;
|
529
|
+
|
530
|
+
Data_Get_Struct(self, MusicTrack, track);
|
531
|
+
|
532
|
+
if (PRIM_NUM_P(rb_at))
|
533
|
+
ts = NUM2DBL(rb_at);
|
534
|
+
else
|
535
|
+
rb_raise(rb_eArgError, "Expected first arg to be a number.");
|
536
|
+
|
537
|
+
if (PRIM_NUM_P(rb_bpm))
|
538
|
+
bpm = NUM2DBL(rb_bpm);
|
539
|
+
else
|
540
|
+
rb_raise(rb_eArgError, "Expected second arg to be a number.");
|
541
|
+
|
542
|
+
require_noerr( err = MusicTrackNewExtendedTempoEvent(*track, ts, bpm), fail );
|
543
|
+
return Qnil;
|
544
|
+
|
545
|
+
fail:
|
546
|
+
RAISE_OSSTATUS(err, "MusicTrackNewExtendedTempoEvent()");
|
547
|
+
}
|
548
|
+
|
549
|
+
static VALUE
|
550
|
+
track_get_loop_info (VALUE self)
|
551
|
+
{
|
552
|
+
MusicTrack *track;
|
553
|
+
UInt32 sz;
|
554
|
+
MusicTrackLoopInfo loop_info;
|
555
|
+
OSStatus err;
|
556
|
+
Data_Get_Struct(self, MusicTrack, track);
|
557
|
+
require_noerr( err = MusicTrackGetProperty(*track, kSequenceTrackProperty_LoopInfo, &loop_info, &sz), fail );
|
558
|
+
|
559
|
+
if (sz == sizeof(MusicTrackLoopInfo)) {
|
560
|
+
VALUE rb_loop_info = rb_hash_new();
|
561
|
+
rb_hash_aset(rb_loop_info, rb_sDuration, rb_float_new(loop_info.loopDuration));
|
562
|
+
rb_hash_aset(rb_loop_info, rb_sNumber, INT2NUM(loop_info.numberOfLoops));
|
563
|
+
return rb_loop_info;
|
564
|
+
} else {
|
565
|
+
return Qnil;
|
566
|
+
}
|
567
|
+
|
568
|
+
fail:
|
569
|
+
RAISE_OSSTATUS(err, "MusicTrackGetProperty()");
|
570
|
+
}
|
571
|
+
|
572
|
+
static VALUE
|
573
|
+
track_set_loop_info (VALUE self, VALUE rb_loop_info)
|
574
|
+
{
|
575
|
+
Check_Type(rb_loop_info, T_HASH);
|
576
|
+
MusicTrack *track;
|
577
|
+
MusicTrackLoopInfo loop_info;
|
578
|
+
OSStatus err;
|
579
|
+
Data_Get_Struct(self, MusicTrack, track);
|
580
|
+
loop_info.loopDuration = NUM2DBL(rb_hash_aref(rb_loop_info, rb_sDuration));
|
581
|
+
loop_info.numberOfLoops = NUM2DBL(rb_hash_aref(rb_loop_info, rb_sNumber));
|
582
|
+
|
583
|
+
require_noerr(
|
584
|
+
err = MusicTrackSetProperty(*track, kSequenceTrackProperty_LoopInfo,
|
585
|
+
&loop_info, sizeof(MusicTrackLoopInfo)),
|
586
|
+
fail);
|
587
|
+
|
588
|
+
return Qnil;
|
589
|
+
|
590
|
+
fail:
|
591
|
+
RAISE_OSSTATUS(err, "MusicTrackSetProperty()");
|
592
|
+
}
|
593
|
+
|
594
|
+
static VALUE
|
595
|
+
track_get_offset (VALUE self)
|
596
|
+
{
|
597
|
+
MusicTrack *track;
|
598
|
+
UInt32 sz;
|
599
|
+
MusicTimeStamp offset;
|
600
|
+
OSStatus err;
|
601
|
+
Data_Get_Struct(self, MusicTrack, track);
|
602
|
+
require_noerr( err = MusicTrackGetProperty(*track, kSequenceTrackProperty_OffsetTime, &offset, &sz), fail );
|
603
|
+
|
604
|
+
if (sz == sizeof(MusicTimeStamp))
|
605
|
+
return rb_float_new(offset);
|
606
|
+
else
|
607
|
+
return Qnil;
|
608
|
+
|
609
|
+
fail:
|
610
|
+
RAISE_OSSTATUS(err, "MusicTrackGetProperty()");
|
611
|
+
}
|
612
|
+
|
613
|
+
static VALUE
|
614
|
+
track_set_offset (VALUE self, VALUE rb_offset)
|
615
|
+
{
|
616
|
+
if (!PRIM_NUM_P(rb_offset))
|
617
|
+
rb_raise(rb_eTypeError, "Expected offset to be a number.");
|
618
|
+
MusicTrack *track;
|
619
|
+
MusicTimeStamp offset = NUM2DBL(rb_offset);
|
620
|
+
OSStatus err;
|
621
|
+
Data_Get_Struct(self, MusicTrack, track);
|
622
|
+
|
623
|
+
require_noerr(
|
624
|
+
err = MusicTrackSetProperty(*track, kSequenceTrackProperty_OffsetTime,
|
625
|
+
&offset, sizeof(MusicTimeStamp)),
|
626
|
+
fail);
|
627
|
+
|
628
|
+
return Qnil;
|
629
|
+
|
630
|
+
fail:
|
631
|
+
RAISE_OSSTATUS(err, "MusicTrackSetProperty()");
|
632
|
+
}
|
633
|
+
|
634
|
+
static VALUE
|
635
|
+
track_get_mute (VALUE self)
|
636
|
+
{
|
637
|
+
MusicTrack *track;
|
638
|
+
UInt32 sz;
|
639
|
+
Boolean status;
|
640
|
+
OSStatus err;
|
641
|
+
Data_Get_Struct(self, MusicTrack, track);
|
642
|
+
require_noerr( err = MusicTrackGetProperty(*track, kSequenceTrackProperty_MuteStatus, &status, &sz), fail );
|
643
|
+
|
644
|
+
if (sz == sizeof(Boolean))
|
645
|
+
return status ? Qtrue : Qfalse;
|
646
|
+
else
|
647
|
+
return Qnil;
|
648
|
+
|
649
|
+
fail:
|
650
|
+
RAISE_OSSTATUS(err, "MusicTrackGetProperty()");
|
651
|
+
}
|
652
|
+
|
653
|
+
static VALUE
|
654
|
+
track_set_mute (VALUE self, VALUE rb_status)
|
655
|
+
{
|
656
|
+
MusicTrack *track;
|
657
|
+
Boolean status = RTEST(rb_status);
|
658
|
+
OSStatus err;
|
659
|
+
Data_Get_Struct(self, MusicTrack, track);
|
660
|
+
|
661
|
+
require_noerr(
|
662
|
+
err = MusicTrackSetProperty(*track, kSequenceTrackProperty_MuteStatus,
|
663
|
+
&status, sizeof(Boolean)),
|
664
|
+
fail);
|
665
|
+
|
666
|
+
return Qnil;
|
667
|
+
|
668
|
+
fail:
|
669
|
+
RAISE_OSSTATUS(err, "MusicTrackSetProperty()");
|
670
|
+
}
|
671
|
+
|
672
|
+
static VALUE
|
673
|
+
track_get_solo (VALUE self)
|
674
|
+
{
|
675
|
+
MusicTrack *track;
|
676
|
+
UInt32 sz;
|
677
|
+
Boolean status;
|
678
|
+
OSStatus err;
|
679
|
+
Data_Get_Struct(self, MusicTrack, track);
|
680
|
+
require_noerr(
|
681
|
+
err = MusicTrackGetProperty(*track, kSequenceTrackProperty_SoloStatus,
|
682
|
+
&status, &sz),
|
683
|
+
fail );
|
684
|
+
|
685
|
+
if (sz == sizeof(Boolean))
|
686
|
+
return status ? Qtrue : Qfalse;
|
687
|
+
else
|
688
|
+
return Qnil;
|
689
|
+
|
690
|
+
fail:
|
691
|
+
RAISE_OSSTATUS(err, "MusicTrackGetProperty()");
|
692
|
+
}
|
693
|
+
|
694
|
+
static VALUE
|
695
|
+
track_set_solo (VALUE self, VALUE rb_status)
|
696
|
+
{
|
697
|
+
MusicTrack *track;
|
698
|
+
Boolean status = RTEST(rb_status);
|
699
|
+
OSStatus err;
|
700
|
+
Data_Get_Struct(self, MusicTrack, track);
|
701
|
+
|
702
|
+
require_noerr(
|
703
|
+
err = MusicTrackSetProperty(*track, kSequenceTrackProperty_SoloStatus,
|
704
|
+
&status, sizeof(Boolean)),
|
705
|
+
fail);
|
706
|
+
|
707
|
+
return Qnil;
|
708
|
+
|
709
|
+
fail:
|
710
|
+
RAISE_OSSTATUS(err, "MusicTrackSetProperty()");
|
711
|
+
}
|
712
|
+
|
713
|
+
static VALUE
|
714
|
+
track_get_length (VALUE self)
|
715
|
+
{
|
716
|
+
MusicTrack *track;
|
717
|
+
MusicTimeStamp length;
|
718
|
+
UInt32 sz;
|
719
|
+
OSStatus err;
|
720
|
+
Data_Get_Struct(self, MusicTrack, track);
|
721
|
+
|
722
|
+
require_noerr(
|
723
|
+
err = MusicTrackGetProperty(*track, kSequenceTrackProperty_TrackLength,
|
724
|
+
&length, &sz),
|
725
|
+
fail);
|
726
|
+
|
727
|
+
if (sz == sizeof(MusicTimeStamp))
|
728
|
+
return rb_float_new(length);
|
729
|
+
else
|
730
|
+
return Qnil;
|
731
|
+
|
732
|
+
fail:
|
733
|
+
RAISE_OSSTATUS(err, "MusicTrackGetProperty()");
|
734
|
+
}
|
735
|
+
|
736
|
+
static VALUE
|
737
|
+
track_set_length (VALUE self, VALUE rb_length)
|
738
|
+
{
|
739
|
+
if (!PRIM_NUM_P(rb_length))
|
740
|
+
rb_raise(rb_eTypeError, "Expected length to be a number.");
|
741
|
+
MusicTrack *track;
|
742
|
+
MusicTimeStamp length = NUM2DBL(rb_length);
|
743
|
+
OSStatus err;
|
744
|
+
Data_Get_Struct(self, MusicTrack, track);
|
745
|
+
|
746
|
+
require_noerr(
|
747
|
+
err = MusicTrackSetProperty(*track, kSequenceTrackProperty_TrackLength,
|
748
|
+
&length, sizeof(MusicTimeStamp)),
|
749
|
+
fail);
|
750
|
+
|
751
|
+
return Qnil;
|
752
|
+
|
753
|
+
fail:
|
754
|
+
RAISE_OSSTATUS(err, "MusicTrackGetProperty()");
|
755
|
+
}
|
756
|
+
|
757
|
+
static VALUE
|
758
|
+
track_get_resolution (VALUE self)
|
759
|
+
{
|
760
|
+
MusicTrack *track;
|
761
|
+
SInt16 res;
|
762
|
+
UInt32 sz;
|
763
|
+
OSStatus err;
|
764
|
+
Data_Get_Struct(self, MusicTrack, track);
|
765
|
+
|
766
|
+
require_noerr(
|
767
|
+
err = MusicTrackGetProperty(*track, kSequenceTrackProperty_TimeResolution, &res, &sz),
|
768
|
+
fail);
|
769
|
+
|
770
|
+
if (sz == sizeof(SInt16))
|
771
|
+
return INT2FIX(res);
|
772
|
+
else
|
773
|
+
return Qnil;
|
774
|
+
|
775
|
+
fail:
|
776
|
+
if (paramErr == err)
|
777
|
+
rb_raise(rb_eArgError, "Resolution is only available to the tempo track.");
|
778
|
+
else
|
779
|
+
RAISE_OSSTATUS(err, "MusicTrackGetProperty()");
|
780
|
+
}
|
781
|
+
|
782
|
+
/* TrackCollection defns */
|
783
|
+
|
784
|
+
static MusicSequence*
|
785
|
+
tracks_get_seq (VALUE rb_tracks)
|
786
|
+
{
|
787
|
+
MusicSequence *seq;
|
788
|
+
VALUE rb_seq = rb_iv_get(rb_tracks, "@sequence");
|
789
|
+
Data_Get_Struct(rb_seq, MusicSequence, seq);
|
790
|
+
return seq;
|
791
|
+
}
|
792
|
+
|
793
|
+
static VALUE
|
794
|
+
tracks_size (VALUE self)
|
795
|
+
{
|
796
|
+
MusicSequence *seq = tracks_get_seq(self);
|
797
|
+
UInt32 track_count;
|
798
|
+
OSStatus err;
|
799
|
+
|
800
|
+
require_noerr( err = MusicSequenceGetTrackCount(*seq, &track_count), fail );
|
801
|
+
return UINT2NUM(track_count);
|
802
|
+
|
803
|
+
fail:
|
804
|
+
RAISE_OSSTATUS(err, "MusicSequenceGetTrackCount()");
|
805
|
+
}
|
806
|
+
|
807
|
+
static VALUE
|
808
|
+
tracks_get_ind_track_internal (VALUE self, VALUE rb_key)
|
809
|
+
{
|
810
|
+
if (!FIXNUM_P(rb_key)) rb_raise(rb_eArgError, "Expected key to be a Fixnum.");
|
811
|
+
MusicSequence *seq = tracks_get_seq(self);
|
812
|
+
MusicTrack *track = ALLOC(MusicTrack);
|
813
|
+
VALUE rb_seq = rb_iv_get(self, "@sequence");
|
814
|
+
OSStatus err;
|
815
|
+
|
816
|
+
require_noerr( err = MusicSequenceGetIndTrack(*seq, FIX2INT(rb_key), track), fail );
|
817
|
+
return track_internal_new(rb_seq, track);
|
818
|
+
|
819
|
+
fail:
|
820
|
+
if (err == kAudioToolboxErr_TrackIndexError) {
|
821
|
+
return Qnil;
|
822
|
+
} else {
|
823
|
+
RAISE_OSSTATUS(err, "MusicSequenceGetIndTrack()");
|
824
|
+
}
|
825
|
+
}
|
826
|
+
|
827
|
+
static VALUE
|
828
|
+
tracks_index (VALUE self, VALUE rb_track)
|
829
|
+
{
|
830
|
+
if (rb_cMusicTrack != rb_class_of(rb_track))
|
831
|
+
rb_raise(rb_eArgError, "Expected arg to be a MusicTrack.");
|
832
|
+
|
833
|
+
MusicSequence *seq = tracks_get_seq(self);
|
834
|
+
MusicTrack *track;
|
835
|
+
UInt32 i;
|
836
|
+
OSStatus err;
|
837
|
+
|
838
|
+
Data_Get_Struct(rb_track, MusicTrack, track);
|
839
|
+
require_noerr( err = MusicSequenceGetTrackIndex(*seq, *track, &i), fail );
|
840
|
+
return UINT2NUM(i);
|
841
|
+
|
842
|
+
fail:
|
843
|
+
RAISE_OSSTATUS(err, "MusicSequenceGetTrackIndex()");
|
844
|
+
}
|
845
|
+
|
846
|
+
static VALUE
|
847
|
+
tracks_tempo_internal (VALUE self)
|
848
|
+
{
|
849
|
+
MusicSequence *seq = tracks_get_seq(self);
|
850
|
+
VALUE rb_seq = rb_iv_get(self, "@sequence");
|
851
|
+
MusicTrack *track = ALLOC(MusicTrack);
|
852
|
+
OSStatus err;
|
853
|
+
|
854
|
+
require_noerr( err = MusicSequenceGetTempoTrack(*seq, track), fail );
|
855
|
+
return track_internal_new(rb_seq, track);
|
856
|
+
|
857
|
+
fail:
|
858
|
+
RAISE_OSSTATUS(err, "MusicSequenceGetTempoTrack()");
|
859
|
+
}
|
860
|
+
|
861
|
+
static VALUE
|
862
|
+
tracks_delete_internal (VALUE self, VALUE rb_track)
|
863
|
+
{
|
864
|
+
MusicSequence *seq = tracks_get_seq(self);
|
865
|
+
MusicTrack *track;
|
866
|
+
OSStatus err;
|
867
|
+
|
868
|
+
Data_Get_Struct(rb_track, MusicTrack, track);
|
869
|
+
require_noerr( err = MusicSequenceDisposeTrack(*seq, *track), fail );
|
870
|
+
return Qnil;
|
871
|
+
|
872
|
+
fail:
|
873
|
+
RAISE_OSSTATUS(err, "MusicSequenceDisposeTrack()");
|
874
|
+
}
|
875
|
+
|
876
|
+
/* MIDINoteMessage */
|
877
|
+
|
878
|
+
static void
|
879
|
+
midi_note_message_free (MIDINoteMessage *msg)
|
880
|
+
{
|
881
|
+
if (msg) free(msg);
|
882
|
+
}
|
883
|
+
|
884
|
+
static VALUE
|
885
|
+
midi_note_message_alloc (VALUE class)
|
886
|
+
{
|
887
|
+
MIDINoteMessage *msg;
|
888
|
+
return Data_Make_Struct(class, MIDINoteMessage, 0, midi_note_message_free, msg);
|
889
|
+
}
|
890
|
+
|
891
|
+
static VALUE
|
892
|
+
midi_note_message_init (VALUE self, VALUE rb_opts)
|
893
|
+
{
|
894
|
+
Check_Type(rb_opts, T_HASH);
|
895
|
+
MIDINoteMessage *msg;
|
896
|
+
VALUE rb_chn, rb_note, rb_vel, rb_rel_vel, rb_dur;
|
897
|
+
|
898
|
+
Data_Get_Struct(self, MIDINoteMessage, msg);
|
899
|
+
|
900
|
+
rb_chn = rb_hash_aref(rb_opts, rb_sChannel);
|
901
|
+
msg->channel = FIXNUM_P(rb_chn) ? FIX2UINT(rb_chn) : 1;
|
902
|
+
|
903
|
+
rb_note = rb_hash_aref(rb_opts, rb_sNote);
|
904
|
+
if (FIXNUM_P(rb_note))
|
905
|
+
msg->note = FIX2UINT(rb_note);
|
906
|
+
else
|
907
|
+
rb_raise(rb_eArgError, ":note is required.");
|
908
|
+
|
909
|
+
rb_vel = rb_hash_aref(rb_opts, rb_sVelocity);
|
910
|
+
msg->velocity = FIXNUM_P(rb_vel) ? FIX2UINT(rb_vel) : 64;
|
911
|
+
|
912
|
+
rb_rel_vel = rb_hash_aref(rb_opts, rb_sReleaseVelocity);
|
913
|
+
msg->releaseVelocity = FIXNUM_P(rb_rel_vel) ? FIX2UINT(rb_rel_vel) : 0;
|
914
|
+
|
915
|
+
rb_dur = rb_hash_aref(rb_opts, rb_sDuration);
|
916
|
+
msg->duration = (MusicTimeStamp) (PRIM_NUM_P(rb_dur)) ? NUM2DBL(rb_dur) : 1.0;
|
917
|
+
|
918
|
+
return self;
|
919
|
+
}
|
920
|
+
|
921
|
+
static VALUE
|
922
|
+
midi_note_message_channel (VALUE self)
|
923
|
+
{
|
924
|
+
MIDINoteMessage *msg;
|
925
|
+
Data_Get_Struct(self, MIDINoteMessage, msg);
|
926
|
+
return UINT2NUM(msg->channel);
|
927
|
+
}
|
928
|
+
|
929
|
+
static VALUE
|
930
|
+
midi_note_message_note (VALUE self)
|
931
|
+
{
|
932
|
+
MIDINoteMessage *msg;
|
933
|
+
Data_Get_Struct(self, MIDINoteMessage, msg);
|
934
|
+
return UINT2NUM(msg->note);
|
935
|
+
}
|
936
|
+
|
937
|
+
static VALUE
|
938
|
+
midi_note_message_velocity (VALUE self)
|
939
|
+
{
|
940
|
+
MIDINoteMessage *msg;
|
941
|
+
Data_Get_Struct(self, MIDINoteMessage, msg);
|
942
|
+
return UINT2NUM(msg->velocity);
|
943
|
+
}
|
944
|
+
|
945
|
+
static VALUE
|
946
|
+
midi_note_message_release_velocity (VALUE self)
|
947
|
+
{
|
948
|
+
MIDINoteMessage *msg;
|
949
|
+
Data_Get_Struct(self, MIDINoteMessage, msg);
|
950
|
+
return UINT2NUM(msg->releaseVelocity);
|
951
|
+
}
|
952
|
+
|
953
|
+
static VALUE
|
954
|
+
midi_note_message_duration (VALUE self)
|
955
|
+
{
|
956
|
+
MIDINoteMessage *msg;
|
957
|
+
Data_Get_Struct(self, MIDINoteMessage, msg);
|
958
|
+
return UINT2NUM(msg->duration);
|
959
|
+
}
|
960
|
+
|
961
|
+
static VALUE
|
962
|
+
midi_note_message_from_const (MIDINoteMessage *msg)
|
963
|
+
{
|
964
|
+
VALUE rb_opts;
|
965
|
+
rb_opts = rb_hash_new();
|
966
|
+
rb_hash_aset(rb_opts, rb_sChannel, INT2NUM(msg->channel));
|
967
|
+
rb_hash_aset(rb_opts, rb_sNote, INT2NUM(msg->note));
|
968
|
+
rb_hash_aset(rb_opts, rb_sVelocity, INT2NUM(msg->velocity));
|
969
|
+
rb_hash_aset(rb_opts, rb_sReleaseVelocity, INT2NUM(msg->releaseVelocity));
|
970
|
+
rb_hash_aset(rb_opts, rb_sDuration, rb_float_new(msg->duration));
|
971
|
+
return rb_funcall(rb_cMIDINoteMessage, rb_intern("new"), 1, rb_opts);
|
972
|
+
}
|
973
|
+
|
974
|
+
/* MIDIChannelMessage */
|
975
|
+
|
976
|
+
static void
|
977
|
+
midi_channel_message_free (MIDIChannelMessage *msg)
|
978
|
+
{
|
979
|
+
if (msg) free(msg);
|
980
|
+
}
|
981
|
+
|
982
|
+
static VALUE
|
983
|
+
midi_channel_message_alloc (VALUE class)
|
984
|
+
{
|
985
|
+
MIDIChannelMessage *msg;
|
986
|
+
return Data_Make_Struct(class, MIDIChannelMessage, 0, midi_channel_message_free, msg);
|
987
|
+
}
|
988
|
+
|
989
|
+
static VALUE
|
990
|
+
midi_channel_message_init (VALUE self, VALUE rb_opts)
|
991
|
+
{
|
992
|
+
Check_Type(rb_opts, T_HASH);
|
993
|
+
MIDIChannelMessage *msg;
|
994
|
+
VALUE rb_status, rb_data1, rb_data2;
|
995
|
+
|
996
|
+
Data_Get_Struct(self, MIDIChannelMessage, msg);
|
997
|
+
|
998
|
+
rb_status = rb_hash_aref(rb_opts, rb_sStatus);
|
999
|
+
if (!FIXNUM_P(rb_status))
|
1000
|
+
rb_raise(rb_eArgError, ":status is required.");
|
1001
|
+
else
|
1002
|
+
msg->status = NUM2DBL(rb_status);
|
1003
|
+
|
1004
|
+
rb_data1 = rb_hash_aref(rb_opts, rb_sData1);
|
1005
|
+
if (!NIL_P(rb_data1)) msg->data1 = (UInt8) FIX2INT(rb_data1);
|
1006
|
+
|
1007
|
+
rb_data2 = rb_hash_aref(rb_opts, rb_sData2);
|
1008
|
+
if (!NIL_P(rb_data2)) msg->data2 = (UInt8) FIX2INT(rb_data2);
|
1009
|
+
|
1010
|
+
return self;
|
1011
|
+
}
|
1012
|
+
|
1013
|
+
static VALUE
|
1014
|
+
midi_channel_message_status (VALUE self)
|
1015
|
+
{
|
1016
|
+
MIDIChannelMessage *msg;
|
1017
|
+
Data_Get_Struct(self, MIDIChannelMessage, msg);
|
1018
|
+
return UINT2NUM(msg->status);
|
1019
|
+
}
|
1020
|
+
|
1021
|
+
static VALUE
|
1022
|
+
midi_channel_message_data1 (VALUE self)
|
1023
|
+
{
|
1024
|
+
MIDIChannelMessage *msg;
|
1025
|
+
Data_Get_Struct(self, MIDIChannelMessage, msg);
|
1026
|
+
return UINT2NUM(msg->data1);
|
1027
|
+
}
|
1028
|
+
|
1029
|
+
static VALUE
|
1030
|
+
midi_channel_message_data2 (VALUE self)
|
1031
|
+
{
|
1032
|
+
MIDIChannelMessage *msg;
|
1033
|
+
Data_Get_Struct(self, MIDIChannelMessage, msg);
|
1034
|
+
return UINT2NUM(msg->data2);
|
1035
|
+
}
|
1036
|
+
|
1037
|
+
static VALUE
|
1038
|
+
midi_channel_message_from_const (MIDIChannelMessage *msg)
|
1039
|
+
{
|
1040
|
+
VALUE rb_opts = rb_hash_new();
|
1041
|
+
switch(msg->status >> 4) {
|
1042
|
+
case 0xA: // key pressure
|
1043
|
+
rb_hash_aset(rb_opts, rb_sChannel, INT2NUM(msg->status ^ 0xA0));
|
1044
|
+
rb_hash_aset(rb_opts, rb_sNote, INT2NUM(msg->data1));
|
1045
|
+
rb_hash_aset(rb_opts, rb_sPressure, INT2NUM(msg->data2));
|
1046
|
+
return rb_funcall(rb_cMIDIKeyPressureMessage, rb_intern("new"), 1, rb_opts);
|
1047
|
+
case 0xB: // control change
|
1048
|
+
rb_hash_aset(rb_opts, rb_sChannel, INT2NUM(msg->status ^ 0xB0));
|
1049
|
+
rb_hash_aset(rb_opts, rb_sNumber, INT2NUM(msg->data1));
|
1050
|
+
rb_hash_aset(rb_opts, rb_sValue, INT2NUM(msg->data2));
|
1051
|
+
return rb_funcall(rb_cMIDIControlChangeMessage, rb_intern("new"), 1, rb_opts);
|
1052
|
+
case 0xC: // program change
|
1053
|
+
rb_hash_aset(rb_opts, rb_sChannel, INT2NUM(msg->status ^ 0xC0));
|
1054
|
+
rb_hash_aset(rb_opts, rb_sProgram, INT2NUM(msg->data1));
|
1055
|
+
return rb_funcall(rb_cMIDIProgramChangeMessage, rb_intern("new"), 1, rb_opts);
|
1056
|
+
case 0xD: // channel pressure
|
1057
|
+
rb_hash_aset(rb_opts, rb_sChannel, INT2NUM(msg->status ^ 0xD0));
|
1058
|
+
rb_hash_aset(rb_opts, rb_sPressure, INT2NUM(msg->data1));
|
1059
|
+
return rb_funcall(rb_cMIDIChannelPressureMessage, rb_intern("new"), 1, rb_opts);
|
1060
|
+
case 0xE: // pitch bend
|
1061
|
+
rb_hash_aset(rb_opts, rb_sChannel, INT2NUM(msg->status ^ 0xE0));
|
1062
|
+
rb_hash_aset(rb_opts, rb_sValue, INT2NUM(msg->data1));
|
1063
|
+
return rb_funcall(rb_cMIDIPitchBendMessage, rb_intern("new"), 1, rb_opts);
|
1064
|
+
default:
|
1065
|
+
rb_raise(rb_eRuntimeError, "Unrecognized message type.");
|
1066
|
+
}
|
1067
|
+
}
|
1068
|
+
|
1069
|
+
/* ExtendedTempoEvent defns */
|
1070
|
+
static VALUE
|
1071
|
+
tempo_from_const (ExtendedTempoEvent *ev)
|
1072
|
+
{
|
1073
|
+
VALUE rb_opts = rb_hash_new();
|
1074
|
+
rb_hash_aset(rb_opts, rb_sBpm, rb_float_new(ev->bpm));
|
1075
|
+
return rb_funcall(rb_cExtendedTempoEvent, rb_intern("new"), 1, rb_opts);
|
1076
|
+
}
|
1077
|
+
|
1078
|
+
/* MusicEventIterator defns */
|
1079
|
+
static void
|
1080
|
+
iter_free (MusicEventIterator *iter)
|
1081
|
+
{
|
1082
|
+
OSStatus err;
|
1083
|
+
require_noerr( err = DisposeMusicEventIterator(*iter), fail );
|
1084
|
+
return;
|
1085
|
+
|
1086
|
+
fail:
|
1087
|
+
rb_warning("DisposeMusicEventIterator() failed with OSStatus %i.", (int) err);
|
1088
|
+
}
|
1089
|
+
|
1090
|
+
static VALUE
|
1091
|
+
iter_alloc (VALUE class)
|
1092
|
+
{
|
1093
|
+
MusicEventIterator *iter;
|
1094
|
+
return Data_Make_Struct(rb_cMusicEventIterator, MusicEventIterator, 0, iter_free, iter);
|
1095
|
+
}
|
1096
|
+
|
1097
|
+
static VALUE
|
1098
|
+
iter_init (VALUE self, VALUE rb_track)
|
1099
|
+
{
|
1100
|
+
MusicTrack *track;
|
1101
|
+
MusicEventIterator *iter;
|
1102
|
+
OSStatus err;
|
1103
|
+
Data_Get_Struct(rb_track, MusicTrack, track);
|
1104
|
+
Data_Get_Struct(self, MusicEventIterator, iter);
|
1105
|
+
require_noerr( err = NewMusicEventIterator(*track, iter), fail );
|
1106
|
+
return self;
|
1107
|
+
|
1108
|
+
fail:
|
1109
|
+
RAISE_OSSTATUS(err, "NewMusicEventIterator()");
|
1110
|
+
}
|
1111
|
+
|
1112
|
+
static VALUE
|
1113
|
+
iter_seek (VALUE self, VALUE rb_time)
|
1114
|
+
{
|
1115
|
+
MusicEventIterator *iter;
|
1116
|
+
MusicTimeStamp ts;
|
1117
|
+
OSStatus err;
|
1118
|
+
Data_Get_Struct(self, MusicEventIterator, iter);
|
1119
|
+
if (PRIM_NUM_P(rb_time))
|
1120
|
+
ts = NUM2DBL(rb_time);
|
1121
|
+
else
|
1122
|
+
rb_raise(rb_eArgError, "Expected first arg to be a number.");
|
1123
|
+
require_noerr( err = MusicEventIteratorSeek(*iter, ts), fail );
|
1124
|
+
return Qnil;
|
1125
|
+
|
1126
|
+
fail:
|
1127
|
+
RAISE_OSSTATUS(err, "MusicEventIteratorSeek()");
|
1128
|
+
}
|
1129
|
+
|
1130
|
+
static VALUE
|
1131
|
+
iter_next (VALUE self)
|
1132
|
+
{
|
1133
|
+
MusicEventIterator *iter;
|
1134
|
+
OSStatus err;
|
1135
|
+
Data_Get_Struct(self, MusicEventIterator, iter);
|
1136
|
+
require_noerr( err = MusicEventIteratorNextEvent(*iter), fail );
|
1137
|
+
return Qnil;
|
1138
|
+
|
1139
|
+
fail:
|
1140
|
+
RAISE_OSSTATUS(err, "MusicEventIteratorNextEvent()");
|
1141
|
+
}
|
1142
|
+
|
1143
|
+
static VALUE
|
1144
|
+
iter_prev (VALUE self)
|
1145
|
+
{
|
1146
|
+
MusicEventIterator *iter;
|
1147
|
+
OSStatus err;
|
1148
|
+
Data_Get_Struct(self, MusicEventIterator, iter);
|
1149
|
+
require_noerr( err = MusicEventIteratorPreviousEvent(*iter), fail );
|
1150
|
+
return Qnil;
|
1151
|
+
|
1152
|
+
fail:
|
1153
|
+
RAISE_OSSTATUS(err, "MusicEventIteratorPreviousEvent()");
|
1154
|
+
}
|
1155
|
+
|
1156
|
+
static VALUE
|
1157
|
+
iter_has_current (VALUE self)
|
1158
|
+
{
|
1159
|
+
MusicEventIterator *iter;
|
1160
|
+
Boolean has_cur;
|
1161
|
+
OSStatus err;
|
1162
|
+
Data_Get_Struct(self, MusicEventIterator, iter);
|
1163
|
+
require_noerr( err = MusicEventIteratorHasCurrentEvent(*iter, &has_cur), fail );
|
1164
|
+
return has_cur ? Qtrue : Qfalse;
|
1165
|
+
|
1166
|
+
fail:
|
1167
|
+
RAISE_OSSTATUS(err, "MusicEventIteratorHasCurrentEvent()");
|
1168
|
+
}
|
1169
|
+
|
1170
|
+
static VALUE
|
1171
|
+
iter_has_prev (VALUE self)
|
1172
|
+
{
|
1173
|
+
MusicEventIterator *iter;
|
1174
|
+
Boolean has_prev;
|
1175
|
+
OSStatus err;
|
1176
|
+
Data_Get_Struct(self, MusicEventIterator, iter);
|
1177
|
+
require_noerr( err = MusicEventIteratorHasPreviousEvent(*iter, &has_prev), fail );
|
1178
|
+
return has_prev ? Qtrue : Qfalse;
|
1179
|
+
|
1180
|
+
fail:
|
1181
|
+
RAISE_OSSTATUS(err, "MusicEventIteratorHasPreviousEvent()");
|
1182
|
+
}
|
1183
|
+
|
1184
|
+
static VALUE
|
1185
|
+
iter_has_next (VALUE self)
|
1186
|
+
{
|
1187
|
+
MusicEventIterator *iter;
|
1188
|
+
Boolean has_next;
|
1189
|
+
OSStatus err;
|
1190
|
+
Data_Get_Struct(self, MusicEventIterator, iter);
|
1191
|
+
require_noerr( err = MusicEventIteratorHasNextEvent(*iter, &has_next), fail );
|
1192
|
+
return has_next ? Qtrue : Qfalse;
|
1193
|
+
|
1194
|
+
fail:
|
1195
|
+
RAISE_OSSTATUS(err, "MusicEventIteratorHasNextEvent()");
|
1196
|
+
}
|
1197
|
+
|
1198
|
+
static VALUE
|
1199
|
+
iter_get_time (VALUE self)
|
1200
|
+
{
|
1201
|
+
MusicEventIterator *iter;
|
1202
|
+
MusicTimeStamp ts;
|
1203
|
+
OSStatus err;
|
1204
|
+
Data_Get_Struct(self, MusicEventIterator, iter);
|
1205
|
+
require_noerr( err = MusicEventIteratorGetEventInfo(*iter, &ts, NULL, NULL, NULL), fail );
|
1206
|
+
return rb_float_new(ts);
|
1207
|
+
|
1208
|
+
fail:
|
1209
|
+
RAISE_OSSTATUS(err, "MusicEventIteratorGetEventInfo()");
|
1210
|
+
}
|
1211
|
+
|
1212
|
+
static VALUE
|
1213
|
+
iter_set_time (VALUE self, VALUE rb_time)
|
1214
|
+
{
|
1215
|
+
MusicEventIterator *iter;
|
1216
|
+
MusicTimeStamp ts = NUM2DBL(rb_time);
|
1217
|
+
OSStatus err;
|
1218
|
+
Data_Get_Struct(self, MusicEventIterator, iter);
|
1219
|
+
require_noerr( err = MusicEventIteratorSetEventTime(*iter, ts), fail );
|
1220
|
+
return Qnil;
|
1221
|
+
|
1222
|
+
fail:
|
1223
|
+
RAISE_OSSTATUS(err, "MusicEventIteratorSetEventTime()");
|
1224
|
+
}
|
1225
|
+
|
1226
|
+
static VALUE
|
1227
|
+
iter_get_event (VALUE self)
|
1228
|
+
{
|
1229
|
+
MusicEventIterator *iter;
|
1230
|
+
MusicEventType type;
|
1231
|
+
const void *data;
|
1232
|
+
OSStatus err;
|
1233
|
+
Data_Get_Struct(self, MusicEventIterator, iter);
|
1234
|
+
require_noerr( err = MusicEventIteratorGetEventInfo(*iter, NULL, &type, &data, NULL), fail );
|
1235
|
+
|
1236
|
+
switch(type) {
|
1237
|
+
case kMusicEventType_NULL:
|
1238
|
+
return Qnil;
|
1239
|
+
case kMusicEventType_MIDINoteMessage:
|
1240
|
+
return midi_note_message_from_const((MIDINoteMessage*) data);
|
1241
|
+
case kMusicEventType_MIDIChannelMessage:
|
1242
|
+
return midi_channel_message_from_const((MIDIChannelMessage*) data);
|
1243
|
+
case kMusicEventType_ExtendedTempo:
|
1244
|
+
return tempo_from_const((ExtendedTempoEvent*) data);
|
1245
|
+
default:
|
1246
|
+
rb_raise(rb_eNotImpError, "Unsupported event type.");
|
1247
|
+
break;
|
1248
|
+
}
|
1249
|
+
|
1250
|
+
fail:
|
1251
|
+
RAISE_OSSTATUS(err, "MusicEventIteratorGetEventInfo()");
|
1252
|
+
}
|
1253
|
+
|
1254
|
+
static VALUE
|
1255
|
+
iter_set_event (VALUE self, VALUE rb_msg)
|
1256
|
+
{
|
1257
|
+
MusicEventIterator *iter;
|
1258
|
+
MusicEventType type;
|
1259
|
+
const void *data;
|
1260
|
+
OSStatus err;
|
1261
|
+
|
1262
|
+
Data_Get_Struct(self, MusicEventIterator, iter);
|
1263
|
+
|
1264
|
+
if (THRQL(rb_cMIDINoteMessage, rb_msg)) {
|
1265
|
+
type = kMusicEventType_MIDINoteMessage;
|
1266
|
+
Data_Get_Struct(rb_msg, MIDINoteMessage, data);
|
1267
|
+
} else if (THRQL(rb_cMIDIChannelMessage, rb_msg)) {
|
1268
|
+
type = kMusicEventType_MIDIChannelMessage;
|
1269
|
+
Data_Get_Struct(rb_msg, MIDIChannelMessage, data);
|
1270
|
+
} else if (THRQL(rb_cExtendedTempoEvent, rb_msg)) {
|
1271
|
+
type = kMusicEventType_ExtendedTempo;
|
1272
|
+
ExtendedTempoEvent tmp;
|
1273
|
+
tmp.bpm = NUM2DBL(rb_funcall(rb_msg, rb_intern("bpm"), 0));
|
1274
|
+
data = &tmp;
|
1275
|
+
} else {
|
1276
|
+
rb_raise(rb_eTypeError, "Unrecognized event type");
|
1277
|
+
}
|
1278
|
+
|
1279
|
+
require_noerr( err = MusicEventIteratorSetEventInfo(*iter, type, data), fail );
|
1280
|
+
return Qnil;
|
1281
|
+
|
1282
|
+
fail:
|
1283
|
+
RAISE_OSSTATUS(err, "MusicEventIteratorSetEventInfo()");
|
1284
|
+
}
|
1285
|
+
|
1286
|
+
static VALUE
|
1287
|
+
iter_delete_event (VALUE self)
|
1288
|
+
{
|
1289
|
+
MusicEventIterator *iter;
|
1290
|
+
OSStatus err;
|
1291
|
+
Data_Get_Struct(self, MusicEventIterator, iter);
|
1292
|
+
require_noerr( err = MusicEventIteratorDeleteEvent(*iter), fail );
|
1293
|
+
return Qnil;
|
1294
|
+
|
1295
|
+
fail:
|
1296
|
+
RAISE_OSSTATUS(err, "MusicEventIteratorDeleteEvent()");
|
1297
|
+
}
|
1298
|
+
|
1299
|
+
/* Initialize extension */
|
1300
|
+
|
1301
|
+
void
|
1302
|
+
Init_music_player ()
|
1303
|
+
{
|
1304
|
+
/*
|
1305
|
+
* CoreMIDI
|
1306
|
+
*/
|
1307
|
+
rb_mCoreMIDI = rb_define_module("CoreMIDI");
|
1308
|
+
rb_define_module_function(rb_mCoreMIDI, "get_number_of_destinations", core_midi_get_number_of_destinations, 0);
|
1309
|
+
rb_define_module_function(rb_mCoreMIDI, "get_destination", core_midi_get_destination, 1);
|
1310
|
+
|
1311
|
+
/*
|
1312
|
+
* AudioToolbox
|
1313
|
+
*/
|
1314
|
+
rb_mAudioToolbox = rb_define_module("AudioToolbox");
|
1315
|
+
|
1316
|
+
/*
|
1317
|
+
* AudioToolbox exceptions
|
1318
|
+
*/
|
1319
|
+
rb_eTrackNotFound = rb_define_class_under(rb_mAudioToolbox, "TrackNotFound", rb_eStandardError);
|
1320
|
+
rb_eEndOfTrack = rb_define_class_under(rb_mAudioToolbox, "EndOfTrack", rb_eStandardError);
|
1321
|
+
rb_eStartOfTrack = rb_define_class_under(rb_mAudioToolbox, "StartOfTrack", rb_eStandardError);
|
1322
|
+
rb_eNoSequence = rb_define_class_under(rb_mAudioToolbox, "NoSequence", rb_eStandardError);
|
1323
|
+
rb_eIllegalTrackDestination = rb_define_class_under(rb_mAudioToolbox, "IllegalTrackDestination", rb_eStandardError);
|
1324
|
+
|
1325
|
+
/* AudioToolbox::MusicPlayer */
|
1326
|
+
rb_cMusicPlayer = rb_define_class_under(rb_mAudioToolbox, "MusicPlayer", rb_cObject);
|
1327
|
+
rb_define_alloc_func(rb_cMusicPlayer, player_alloc);
|
1328
|
+
rb_define_method(rb_cMusicPlayer, "initialize", player_init, 0);
|
1329
|
+
rb_define_method(rb_cMusicPlayer, "playing?", player_is_playing, 0);
|
1330
|
+
rb_define_method(rb_cMusicPlayer, "sequence", player_get_sequence, 0);
|
1331
|
+
rb_define_method(rb_cMusicPlayer, "sequence=", player_set_sequence, 1);
|
1332
|
+
rb_define_method(rb_cMusicPlayer, "start", player_start, 0);
|
1333
|
+
rb_define_method(rb_cMusicPlayer, "stop", player_stop, 0);
|
1334
|
+
rb_define_method(rb_cMusicPlayer, "time", player_get_time, 0);
|
1335
|
+
rb_define_method(rb_cMusicPlayer, "time=", player_set_time, 1);
|
1336
|
+
rb_define_method(rb_cMusicPlayer, "play_rate_scalar", player_get_play_rate_scalar, 0);
|
1337
|
+
rb_define_method(rb_cMusicPlayer, "play_rate_scalar=", player_set_play_rate_scalar, 1);
|
1338
|
+
rb_define_method(rb_cMusicPlayer, "host_time_for_beats", player_host_time_for_beats, 1);
|
1339
|
+
|
1340
|
+
/* AudioToolbox::MusicSequence */
|
1341
|
+
rb_cMusicSequence = rb_define_class_under(rb_mAudioToolbox, "MusicSequence", rb_cObject);
|
1342
|
+
rb_define_alloc_func(rb_cMusicSequence, sequence_alloc);
|
1343
|
+
rb_define_method(rb_cMusicSequence, "initialize", sequence_init, 0);
|
1344
|
+
rb_define_private_method(rb_cMusicSequence, "load_internal", sequence_load, 1);
|
1345
|
+
rb_define_method(rb_cMusicSequence, "midi_endpoint=", sequence_set_midi_endpoint, 1);
|
1346
|
+
rb_define_method(rb_cMusicSequence, "type", sequence_get_type, 0);
|
1347
|
+
rb_define_method(rb_cMusicSequence, "type=", sequence_set_type, 1);
|
1348
|
+
rb_define_method(rb_cMusicSequence, "save", sequence_save, 1);
|
1349
|
+
|
1350
|
+
/* AudioToolbox::MusicTrack */
|
1351
|
+
rb_cMusicTrack = rb_define_class_under(rb_mAudioToolbox, "MusicTrack", rb_cObject);
|
1352
|
+
rb_define_singleton_method(rb_cMusicTrack, "new", track_new, -1);
|
1353
|
+
rb_define_method(rb_cMusicTrack, "initialize", track_init, -1);
|
1354
|
+
rb_define_method(rb_cMusicTrack, "add_midi_note_message", track_add_midi_note_message, 2);
|
1355
|
+
rb_define_method(rb_cMusicTrack, "add_midi_channel_message", track_add_midi_channel_message, 2);
|
1356
|
+
rb_define_method(rb_cMusicTrack, "add_extended_tempo_event", track_add_extended_tempo_event, 2);
|
1357
|
+
rb_define_method(rb_cMusicTrack, "loop_info", track_get_loop_info, 0);
|
1358
|
+
rb_define_method(rb_cMusicTrack, "loop_info=", track_set_loop_info, 1);
|
1359
|
+
rb_define_method(rb_cMusicTrack, "offset", track_get_offset, 0);
|
1360
|
+
rb_define_method(rb_cMusicTrack, "offset=", track_set_offset, 1);
|
1361
|
+
rb_define_method(rb_cMusicTrack, "mute", track_get_mute, 0);
|
1362
|
+
rb_define_method(rb_cMusicTrack, "mute=", track_set_mute, 1);
|
1363
|
+
rb_define_method(rb_cMusicTrack, "solo", track_get_solo, 0);
|
1364
|
+
rb_define_method(rb_cMusicTrack, "solo=", track_set_solo, 1);
|
1365
|
+
rb_define_method(rb_cMusicTrack, "length", track_get_length, 0);
|
1366
|
+
rb_define_method(rb_cMusicTrack, "length=", track_set_length, 1);
|
1367
|
+
rb_define_method(rb_cMusicTrack, "resolution", track_get_resolution, 0);
|
1368
|
+
|
1369
|
+
/* AudioToolbox::MusicSequence#tracks proxy */
|
1370
|
+
rb_cMusicTrackCollection = rb_define_class_under(rb_mAudioToolbox, "MusicTrackCollection", rb_cObject);
|
1371
|
+
rb_define_method(rb_cMusicTrackCollection, "size", tracks_size, 0);
|
1372
|
+
rb_define_method(rb_cMusicTrackCollection, "index", tracks_index, 1);
|
1373
|
+
rb_define_private_method(rb_cMusicTrackCollection, "delete_internal", tracks_delete_internal, 1);
|
1374
|
+
rb_define_private_method(rb_cMusicTrackCollection, "tempo_internal", tracks_tempo_internal, 0);
|
1375
|
+
rb_define_private_method(rb_cMusicTrackCollection, "ind_internal", tracks_get_ind_track_internal, 1);
|
1376
|
+
|
1377
|
+
/* AudioToolbox::MIDINoteMessage */
|
1378
|
+
rb_cMIDINoteMessage = rb_define_class_under(rb_mAudioToolbox, "MIDINoteMessage", rb_cObject);
|
1379
|
+
rb_define_alloc_func(rb_cMIDINoteMessage, midi_note_message_alloc);
|
1380
|
+
rb_define_method(rb_cMIDINoteMessage, "initialize", midi_note_message_init, 1);
|
1381
|
+
rb_define_method(rb_cMIDINoteMessage, "channel", midi_note_message_channel, 0);
|
1382
|
+
rb_define_method(rb_cMIDINoteMessage, "note", midi_note_message_note, 0);
|
1383
|
+
rb_define_method(rb_cMIDINoteMessage, "velocity", midi_note_message_velocity, 0);
|
1384
|
+
rb_define_method(rb_cMIDINoteMessage, "release_velocity", midi_note_message_release_velocity, 0);
|
1385
|
+
rb_define_method(rb_cMIDINoteMessage, "duration", midi_note_message_duration, 0);
|
1386
|
+
|
1387
|
+
/* AudioToolbox::MIDIChannelMessage */
|
1388
|
+
rb_cMIDIChannelMessage = rb_define_class_under(rb_mAudioToolbox, "MIDIChannelMessage", rb_cObject);
|
1389
|
+
rb_cMIDIKeyPressureMessage = rb_define_class_under(rb_mAudioToolbox, "MIDIKeyPressureMessage", rb_cMIDIChannelMessage);
|
1390
|
+
rb_cMIDIControlChangeMessage = rb_define_class_under(rb_mAudioToolbox, "MIDIControlChangeMessage", rb_cMIDIChannelMessage);
|
1391
|
+
rb_cMIDIProgramChangeMessage = rb_define_class_under(rb_mAudioToolbox, "MIDIProgramChangeMessage", rb_cMIDIChannelMessage);
|
1392
|
+
rb_cMIDIChannelPressureMessage = rb_define_class_under(rb_mAudioToolbox, "MIDIChannelPressureMessage", rb_cMIDIChannelMessage);
|
1393
|
+
rb_cMIDIPitchBendMessage = rb_define_class_under(rb_mAudioToolbox, "MIDIPitchBendMessage", rb_cMIDIChannelMessage);
|
1394
|
+
rb_define_alloc_func(rb_cMIDIChannelMessage, midi_channel_message_alloc);
|
1395
|
+
rb_define_method(rb_cMIDIChannelMessage, "initialize", midi_channel_message_init, 1);
|
1396
|
+
rb_define_method(rb_cMIDIChannelMessage, "status", midi_channel_message_status, 0);
|
1397
|
+
rb_define_method(rb_cMIDIChannelMessage, "data1", midi_channel_message_data1, 0);
|
1398
|
+
rb_define_method(rb_cMIDIChannelMessage, "data2", midi_channel_message_data2, 0);
|
1399
|
+
|
1400
|
+
/* AudioToolbox::ExtendedTempoEvent */
|
1401
|
+
rb_cExtendedTempoEvent = rb_define_class_under(rb_mAudioToolbox, "ExtendedTempoEvent", rb_cObject);
|
1402
|
+
|
1403
|
+
/* AudioToolbox::MusicEventIterator */
|
1404
|
+
rb_cMusicEventIterator = rb_define_class_under(rb_mAudioToolbox, "MusicEventIterator", rb_cObject);
|
1405
|
+
rb_define_alloc_func(rb_cMusicEventIterator, iter_alloc);
|
1406
|
+
rb_define_method(rb_cMusicEventIterator, "initialize", iter_init, 1);
|
1407
|
+
rb_define_method(rb_cMusicEventIterator, "seek", iter_seek, 1);
|
1408
|
+
rb_define_method(rb_cMusicEventIterator, "next", iter_next, 0);
|
1409
|
+
rb_define_method(rb_cMusicEventIterator, "prev", iter_prev, 0);
|
1410
|
+
rb_define_method(rb_cMusicEventIterator, "current?", iter_has_current, 0);
|
1411
|
+
rb_define_method(rb_cMusicEventIterator, "next?", iter_has_next, 0);
|
1412
|
+
rb_define_method(rb_cMusicEventIterator, "prev?", iter_has_prev, 0);
|
1413
|
+
rb_define_method(rb_cMusicEventIterator, "time", iter_get_time, 0);
|
1414
|
+
rb_define_method(rb_cMusicEventIterator, "time=", iter_set_time, 1);
|
1415
|
+
rb_define_method(rb_cMusicEventIterator, "event", iter_get_event, 0);
|
1416
|
+
rb_define_method(rb_cMusicEventIterator, "event=", iter_set_event, 1);
|
1417
|
+
rb_define_method(rb_cMusicEventIterator, "delete", iter_delete_event, 0);
|
1418
|
+
|
1419
|
+
/* Symbols */
|
1420
|
+
rb_sBeat = CSTR2SYM("beat");
|
1421
|
+
rb_sBpm = CSTR2SYM("bpm");
|
1422
|
+
rb_sChannel = CSTR2SYM("channel");
|
1423
|
+
rb_sData1 = CSTR2SYM("data1");
|
1424
|
+
rb_sData2 = CSTR2SYM("data2");
|
1425
|
+
rb_sDuration = CSTR2SYM("duration");
|
1426
|
+
rb_sNote = CSTR2SYM("note");
|
1427
|
+
rb_sLength = CSTR2SYM("length");
|
1428
|
+
rb_sLoopInfo = CSTR2SYM("loop_info");
|
1429
|
+
rb_sMute = CSTR2SYM("mute");
|
1430
|
+
rb_sNumber = CSTR2SYM("number");
|
1431
|
+
rb_sPressure = CSTR2SYM("pressure");
|
1432
|
+
rb_sProgram = CSTR2SYM("program");
|
1433
|
+
rb_sReleaseVelocity = CSTR2SYM("release_velocity");
|
1434
|
+
rb_sSamp = CSTR2SYM("samp");
|
1435
|
+
rb_sSecs = CSTR2SYM("secs");
|
1436
|
+
rb_sSolo = CSTR2SYM("solo");
|
1437
|
+
rb_sStatus = CSTR2SYM("status");
|
1438
|
+
rb_sValue = CSTR2SYM("value");
|
1439
|
+
rb_sVelocity = CSTR2SYM("velocity");
|
1440
|
+
}
|