fmod 0.9.0
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.
- checksums.yaml +7 -0
- data/.gitignore +14 -0
- data/.travis.yml +5 -0
- data/.yardopts +2 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +5 -0
- data/LICENSE.txt +21 -0
- data/README.md +96 -0
- data/Rakefile +1 -0
- data/bin/console +28 -0
- data/bin/setup +8 -0
- data/ext/fmod.dll +0 -0
- data/ext/fmod64.dll +0 -0
- data/ext/libfmod.dylib +0 -0
- data/ext/llbfmod.zip +0 -0
- data/extras/FMOD Studio Programmers API for Windows.chm +0 -0
- data/fmod.gemspec +58 -0
- data/lib/fmod.rb +564 -0
- data/lib/fmod/channel.rb +151 -0
- data/lib/fmod/channel_control.rb +821 -0
- data/lib/fmod/channel_group.rb +61 -0
- data/lib/fmod/core.rb +35 -0
- data/lib/fmod/core/bool_description.rb +18 -0
- data/lib/fmod/core/channel_mask.rb +24 -0
- data/lib/fmod/core/data_description.rb +14 -0
- data/lib/fmod/core/driver.rb +59 -0
- data/lib/fmod/core/dsp_description.rb +7 -0
- data/lib/fmod/core/dsp_index.rb +9 -0
- data/lib/fmod/core/dsp_type.rb +43 -0
- data/lib/fmod/core/extensions.rb +28 -0
- data/lib/fmod/core/file_system.rb +86 -0
- data/lib/fmod/core/filter_type.rb +19 -0
- data/lib/fmod/core/float_description.rb +16 -0
- data/lib/fmod/core/guid.rb +50 -0
- data/lib/fmod/core/init_flags.rb +19 -0
- data/lib/fmod/core/integer_description.rb +26 -0
- data/lib/fmod/core/mode.rb +36 -0
- data/lib/fmod/core/output_type.rb +30 -0
- data/lib/fmod/core/parameter_info.rb +41 -0
- data/lib/fmod/core/parameter_type.rb +10 -0
- data/lib/fmod/core/result.rb +88 -0
- data/lib/fmod/core/reverb.rb +217 -0
- data/lib/fmod/core/sound_ex_info.rb +7 -0
- data/lib/fmod/core/sound_format.rb +30 -0
- data/lib/fmod/core/sound_group_behavior.rb +9 -0
- data/lib/fmod/core/sound_type.rb +80 -0
- data/lib/fmod/core/speaker_index.rb +18 -0
- data/lib/fmod/core/speaker_mode.rb +16 -0
- data/lib/fmod/core/spectrum_data.rb +12 -0
- data/lib/fmod/core/structure.rb +23 -0
- data/lib/fmod/core/structures.rb +41 -0
- data/lib/fmod/core/tag.rb +51 -0
- data/lib/fmod/core/tag_data_type.rb +14 -0
- data/lib/fmod/core/time_unit.rb +40 -0
- data/lib/fmod/core/vector.rb +42 -0
- data/lib/fmod/core/window_type.rb +12 -0
- data/lib/fmod/dsp.rb +510 -0
- data/lib/fmod/dsp_connection.rb +113 -0
- data/lib/fmod/effects.rb +38 -0
- data/lib/fmod/effects/channel_mix.rb +101 -0
- data/lib/fmod/effects/chorus.rb +30 -0
- data/lib/fmod/effects/compressor.rb +52 -0
- data/lib/fmod/effects/convolution_reverb.rb +31 -0
- data/lib/fmod/effects/delay.rb +44 -0
- data/lib/fmod/effects/distortion.rb +16 -0
- data/lib/fmod/effects/dsps.rb +10 -0
- data/lib/fmod/effects/echo.rb +37 -0
- data/lib/fmod/effects/envelope_follower.rb +31 -0
- data/lib/fmod/effects/fader.rb +16 -0
- data/lib/fmod/effects/fft.rb +38 -0
- data/lib/fmod/effects/flange.rb +37 -0
- data/lib/fmod/effects/high_pass.rb +24 -0
- data/lib/fmod/effects/high_pass_simple.rb +25 -0
- data/lib/fmod/effects/it_echo.rb +56 -0
- data/lib/fmod/effects/it_lowpass.rb +36 -0
- data/lib/fmod/effects/ladspa_plugin.rb +14 -0
- data/lib/fmod/effects/limiter.rb +32 -0
- data/lib/fmod/effects/loudness_meter.rb +19 -0
- data/lib/fmod/effects/low_pass.rb +25 -0
- data/lib/fmod/effects/low_pass_simple.rb +26 -0
- data/lib/fmod/effects/mixer.rb +11 -0
- data/lib/fmod/effects/multiband_eq.rb +153 -0
- data/lib/fmod/effects/normalize.rb +47 -0
- data/lib/fmod/effects/object_pan.rb +62 -0
- data/lib/fmod/effects/oscillator.rb +52 -0
- data/lib/fmod/effects/pan.rb +166 -0
- data/lib/fmod/effects/param_eq.rb +36 -0
- data/lib/fmod/effects/pitch_shift.rb +47 -0
- data/lib/fmod/effects/return.rb +18 -0
- data/lib/fmod/effects/send.rb +21 -0
- data/lib/fmod/effects/sfx_reverb.rb +87 -0
- data/lib/fmod/effects/three_eq.rb +41 -0
- data/lib/fmod/effects/transceiver.rb +57 -0
- data/lib/fmod/effects/tremolo.rb +67 -0
- data/lib/fmod/effects/vst_plugin.rb +12 -0
- data/lib/fmod/effects/winamp_plugin.rb +12 -0
- data/lib/fmod/error.rb +108 -0
- data/lib/fmod/geometry.rb +380 -0
- data/lib/fmod/handle.rb +129 -0
- data/lib/fmod/reverb3D.rb +98 -0
- data/lib/fmod/sound.rb +810 -0
- data/lib/fmod/sound_group.rb +54 -0
- data/lib/fmod/system.rb +1242 -0
- data/lib/fmod/version.rb +3 -0
- metadata +220 -0
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
|
|
2
|
+
module FMOD
|
|
3
|
+
class SoundGroup < Handle
|
|
4
|
+
|
|
5
|
+
include Fiddle
|
|
6
|
+
include Enumerable
|
|
7
|
+
|
|
8
|
+
integer_reader(:max_audible, :SoundGroup_GetMaxAudible)
|
|
9
|
+
integer_writer(:max_audible=, :SoundGroup_SetMaxAudible)
|
|
10
|
+
|
|
11
|
+
integer_reader(:behavior, :SoundGroup_GetMaxAudibleBehavior)
|
|
12
|
+
integer_writer(:behavior=, :SoundGroup_SetMaxAudibleBehavior)
|
|
13
|
+
|
|
14
|
+
float_reader(:volume, :SoundGroup_GetVolume)
|
|
15
|
+
float_writer(:volume=, :SoundGroup_SetVolume)
|
|
16
|
+
|
|
17
|
+
float_reader(:fade_speed, :SoundGroup_GetMuteFadeSpeed)
|
|
18
|
+
float_writer(:fade_speed=, :SoundGroup_SetMuteFadeSpeed)
|
|
19
|
+
|
|
20
|
+
integer_reader(:count, :SoundGroup_GetNumSounds)
|
|
21
|
+
integer_reader(:playing_count, :SoundGroup_GetNumPlaying)
|
|
22
|
+
|
|
23
|
+
alias_method :size, :count
|
|
24
|
+
|
|
25
|
+
def name
|
|
26
|
+
buffer = "\0" * 512
|
|
27
|
+
FMOD.invoke(:SoundGroup_GetName, self, buffer, 512)
|
|
28
|
+
buffer.delete("\0")
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def each
|
|
32
|
+
return to_enum(:each) unless block_given?
|
|
33
|
+
(0...count).each { |i| yield self[i] }
|
|
34
|
+
self
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def [](index)
|
|
38
|
+
FMOD.valid_range?(0, 0, count - 1)
|
|
39
|
+
FMOD.invoke(:SoundGroup_GetSound, self, index, sound = int_ptr)
|
|
40
|
+
Sound.new(sound)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
alias_method :sound, :[]
|
|
44
|
+
|
|
45
|
+
def parent
|
|
46
|
+
FMOD.invoke(:SoundGroup_GetSystemObject, self, system = int_ptr)
|
|
47
|
+
System.new(system)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def stop
|
|
51
|
+
FMOD.invoke(:SoundGroup_Stop, self)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
data/lib/fmod/system.rb
ADDED
|
@@ -0,0 +1,1242 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
module FMOD
|
|
4
|
+
class System < Handle
|
|
5
|
+
|
|
6
|
+
CpuUsage = Struct.new(:dsp, :stream, :geometry, :update, :total)
|
|
7
|
+
|
|
8
|
+
RamUsage = Struct.new(:current, :max, :total)
|
|
9
|
+
|
|
10
|
+
FileUsage = Struct.new(:sample, :stream, :other)
|
|
11
|
+
|
|
12
|
+
Speaker = Struct.new(:index, :x, :y, :active)
|
|
13
|
+
|
|
14
|
+
Plugin = Struct.new(:handle, :type, :name, :version)
|
|
15
|
+
|
|
16
|
+
SoftwareFormat = Struct.new(:sample_rate, :speaker_mode, :raw_channels)
|
|
17
|
+
|
|
18
|
+
DspBuffer = Struct.new(:size, :count)
|
|
19
|
+
|
|
20
|
+
##
|
|
21
|
+
# The internal buffer size for streams opened after this call. Larger values
|
|
22
|
+
# will consume more memory, whereas smaller values may cause buffer
|
|
23
|
+
# under-run/starvation/stuttering caused by large delays in disk access (ie
|
|
24
|
+
# net-stream), or CPU usage in slow machines, or by trying to play too many
|
|
25
|
+
# streams at once.
|
|
26
|
+
# @attr size [Integer] The size of stream file buffer. Default is 16384.
|
|
27
|
+
# @attr type [Integer] Type of unit for stream file buffer size.
|
|
28
|
+
# @see TimeUnit
|
|
29
|
+
StreamBuffer = Struct.new(:size, :type)
|
|
30
|
+
|
|
31
|
+
def initialize(handle)
|
|
32
|
+
super
|
|
33
|
+
@rolloff_callbacks = []
|
|
34
|
+
sig = [TYPE_VOIDP, TYPE_FLOAT]
|
|
35
|
+
abi = FMOD::ABI
|
|
36
|
+
cb = Closure::BlockCaller.new(TYPE_FLOAT, sig, abi) do |channel, distance|
|
|
37
|
+
unless @rolloff_callbacks.empty?
|
|
38
|
+
chan = Channel.new(channel)
|
|
39
|
+
@rolloff_callbacks.each { |proc| proc.call(chan, distance) }
|
|
40
|
+
end
|
|
41
|
+
distance
|
|
42
|
+
end
|
|
43
|
+
FMOD.invoke(:System_Set3DRolloffCallback, self, cb)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def on_rolloff(proc = nil, &block)
|
|
47
|
+
cb = proc || block
|
|
48
|
+
raise LocalJumpError, "No block given." if cb.nil?
|
|
49
|
+
@rolloff_callbacks << cb
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# @group Speaker Positioning
|
|
53
|
+
|
|
54
|
+
##
|
|
55
|
+
# Generates a "default" matrix based on the specified source and target
|
|
56
|
+
# speaker mode.
|
|
57
|
+
#
|
|
58
|
+
# @param source [Integer] The speaker mode being converted from.
|
|
59
|
+
# @param target [Integer] The speaker mode being converted to.
|
|
60
|
+
#
|
|
61
|
+
# @note _source_ and _target_ must not exceed {FMOD::MAX_CHANNEL_WIDTH}.
|
|
62
|
+
# @see FMOD::MAX_CHANNEL_WIDTH
|
|
63
|
+
# @see SpeakerMode
|
|
64
|
+
#
|
|
65
|
+
# @return [<Array<Array<Float>>] the mix matrix.
|
|
66
|
+
def default_matrix(source, target)
|
|
67
|
+
max = FMOD::MAX_CHANNEL_WIDTH
|
|
68
|
+
raise RangeError, "source channels cannot exceed #{max}" if source > max
|
|
69
|
+
raise RangeError, "target channels cannot exceed #{max}" if target > max
|
|
70
|
+
return [] if source < 1 || target < 1
|
|
71
|
+
buffer = "\0" * (SIZEOF_FLOAT * source * target)
|
|
72
|
+
FMOD.invoke(:System_GetDefaultMixMatrix, self, source, target, buffer, 0)
|
|
73
|
+
buffer.unpack('f*').each_slice(source).to_a
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
##
|
|
77
|
+
# Helper function to return the speakers as array.
|
|
78
|
+
# @return [Array<Speaker>] the array of speakers.
|
|
79
|
+
def speakers
|
|
80
|
+
each_speaker.to_a
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
##
|
|
84
|
+
# @return [Speaker] the current speaker position for the selected speaker.
|
|
85
|
+
# @see SpeakerIndex
|
|
86
|
+
def speaker(index)
|
|
87
|
+
args = ["\0" * SIZEOF_FLOAT, "\0" * SIZEOF_FLOAT, "\0" * SIZEOF_INT ]
|
|
88
|
+
FMOD.invoke(:System_GetSpeakerPosition, self, index, *args)
|
|
89
|
+
args = [index] + args.join.unpack('ffl')
|
|
90
|
+
args[3] = args[3] != 0
|
|
91
|
+
Speaker.new(*args)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
##
|
|
95
|
+
# This function allows the user to specify the position of their actual
|
|
96
|
+
# physical speaker to account for non standard setups.
|
|
97
|
+
#
|
|
98
|
+
# It also allows the user to disable speakers from 3D consideration in a
|
|
99
|
+
# game.
|
|
100
|
+
#
|
|
101
|
+
# The function is for describing the "real world" speaker placement to
|
|
102
|
+
# provide a more natural panning solution for 3D sound. Graphical
|
|
103
|
+
# configuration screens in an application could draw icons for speaker
|
|
104
|
+
# placement that the user could position at their will.
|
|
105
|
+
#
|
|
106
|
+
# @overload set_speaker(speaker)
|
|
107
|
+
# @param speaker [Speaker] The speaker to set.
|
|
108
|
+
# @overload set_speaker(index, x, y, active = true)
|
|
109
|
+
# @param index [Integer] The index of the speaker to set.
|
|
110
|
+
# @see SpeakerIndex
|
|
111
|
+
# @param x [Float] The 2D X position relative to the listener.
|
|
112
|
+
# @param y [Float] The 2D Y position relative to the listener.
|
|
113
|
+
# @param active [Boolean] The active state of a speaker.
|
|
114
|
+
# @return [void]
|
|
115
|
+
def set_speaker(*args)
|
|
116
|
+
unless [1, 3, 4].include?(args.size)
|
|
117
|
+
message = "wrong number of arguments: #{args.size} for 1, 3, or 4"
|
|
118
|
+
raise ArgumentError, message
|
|
119
|
+
end
|
|
120
|
+
index, x, y, active = args[0].is_a?(Speaker) ? args[0].values : args
|
|
121
|
+
active = true if args.size == 3
|
|
122
|
+
FMOD.invoke(:System_SetSpeakerPosition, self, index, x, y, active.to_i)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
##
|
|
126
|
+
# @overload each_speaker
|
|
127
|
+
# When called with a block, yields each speaker in turn before returning
|
|
128
|
+
# self.
|
|
129
|
+
# @yield [speaker] Yields a speaker to the block.
|
|
130
|
+
# @yieldparam speaker [Speaker] The current enumerated speaker.
|
|
131
|
+
# @return [self]
|
|
132
|
+
# @overload each_speaker
|
|
133
|
+
# When called without a block, returns an enumerator for the speakers.
|
|
134
|
+
# @return [Enumerator]
|
|
135
|
+
def each_speaker
|
|
136
|
+
return to_enum(:each_speaker) unless block_given?
|
|
137
|
+
SpeakerIndex.constants(false).each do |const|
|
|
138
|
+
index = SpeakerIndex.const_get(const)
|
|
139
|
+
yield speaker(index) rescue next
|
|
140
|
+
end
|
|
141
|
+
self
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# @!endgroup
|
|
145
|
+
|
|
146
|
+
# @!group Object Creation
|
|
147
|
+
|
|
148
|
+
##
|
|
149
|
+
# @note <b>This must be called to create an {System} object before you can
|
|
150
|
+
# do anything else.</b>
|
|
151
|
+
#
|
|
152
|
+
# {System} creation function. Use this function to create one, or
|
|
153
|
+
# multiple instances of system objects.
|
|
154
|
+
# @param options [Hash] Options hash.
|
|
155
|
+
# @option options [Integer] :max_channels (32) The maximum number of
|
|
156
|
+
# channels to be used in FMOD. They are also called "virtual channels" as
|
|
157
|
+
# you can play as many of these as you want, even if you only have a small
|
|
158
|
+
# number of software voices.
|
|
159
|
+
# @option options [Integer] :flags (InitFlags::NORMAL) See {InitFlags}. This
|
|
160
|
+
# can be a selection of flags bitwise OR'ed together to change the
|
|
161
|
+
# behavior of FMOD at initialization time.
|
|
162
|
+
# @option options [Pointer|String] :driver_data (FMOD::NULL) Driver
|
|
163
|
+
# specific data that can be passed to the output plugin. For example the
|
|
164
|
+
# filename for the wav writer plugin.
|
|
165
|
+
# @return [System] the newly created {System} object.
|
|
166
|
+
def self.create(**options)
|
|
167
|
+
max = [options[:max_channels] || 32, 4093].min
|
|
168
|
+
flags = options[:flags] || InitFlags::NORMAL
|
|
169
|
+
driver = options[:driver_data] || FMOD::NULL
|
|
170
|
+
FMOD.invoke(:System_Create, address = "\0" * SIZEOF_INTPTR_T)
|
|
171
|
+
system = new(address)
|
|
172
|
+
FMOD.invoke(:System_Init, system, max, flags, driver)
|
|
173
|
+
system
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
##
|
|
177
|
+
# Loads a sound into memory, or opens it for streaming.
|
|
178
|
+
#
|
|
179
|
+
# @param source [String, Pointer] Name of the file or URL to open encoded in
|
|
180
|
+
# a UTF-8 string, or a pointer to a pre-loaded sound memory block if
|
|
181
|
+
# {Mode::OPEN_MEMORY} / {Mode::OPEN_MEMORY_POINT} is used.
|
|
182
|
+
# @param options [Hash] Options hash.
|
|
183
|
+
# @option options [Integer] :mode (Mode::DEFAULT) Behavior modifier for
|
|
184
|
+
# opening the sound. See {Mode} for explanation of flags.
|
|
185
|
+
# @option options [SoundExInfo] :extra (FMOD::NULL) Extra data which lets
|
|
186
|
+
# the user provide extended information while playing the sound.
|
|
187
|
+
# @return [Sound] the created sound.
|
|
188
|
+
def create_sound(source, **options)
|
|
189
|
+
mode = options[:mode] || Mode::DEFAULT
|
|
190
|
+
extra = options[:extra] || FMOD::NULL
|
|
191
|
+
sound = int_ptr
|
|
192
|
+
FMOD.invoke(:System_CreateSound, self, source, mode, extra, sound)
|
|
193
|
+
Sound.new(sound)
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
##
|
|
197
|
+
# Opens a sound for streaming. This function is a helper function that is
|
|
198
|
+
# the same as {#create_sound} but has the {Mode::CREATE_STREAM} flag added
|
|
199
|
+
# internally.
|
|
200
|
+
#
|
|
201
|
+
# @param source [String, Pointer] Name of the file or URL to open encoded in
|
|
202
|
+
# a UTF-8 string, or a pointer to a pre-loaded sound memory block if
|
|
203
|
+
# {Mode::OPEN_MEMORY} / {Mode::OPEN_MEMORY_POINT} is used.
|
|
204
|
+
# @param options [Hash] Options hash.
|
|
205
|
+
# @option options [Integer] :mode (Mode::DEFAULT) Behavior modifier for
|
|
206
|
+
# opening the sound. See {Mode} for explanation of flags.
|
|
207
|
+
# @option options [SoundExInfo] :extra (FMOD::NULL) Extra data which lets
|
|
208
|
+
# the user provide extended information while playing the sound.
|
|
209
|
+
# @return [Sound] the created sound.
|
|
210
|
+
def create_stream(source, **options)
|
|
211
|
+
mode = options[:mode] || Mode::DEFAULT
|
|
212
|
+
extra = options[:extra] || FMOD::NULL
|
|
213
|
+
sound = int_ptr
|
|
214
|
+
FMOD.invoke(:System_CreateSound, self, source, mode, extra, sound)
|
|
215
|
+
Sound.new(sound)
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
##
|
|
219
|
+
# Creates an FMOD defined built in DSP unit object to be inserted into a DSP
|
|
220
|
+
# network, for the purposes of sound filtering or sound generation.
|
|
221
|
+
#
|
|
222
|
+
# This function is used to create special effects that come built into FMOD.
|
|
223
|
+
#
|
|
224
|
+
# @param type [Integer, Class] A pre-defined DSP effect or sound generator
|
|
225
|
+
# described by in {DspType}, or a Class found within the {Effects} module.
|
|
226
|
+
#
|
|
227
|
+
# @return [Dsp] the created DSP.
|
|
228
|
+
def create_dsp(type)
|
|
229
|
+
unless FMOD.type?(type, Integer, false)
|
|
230
|
+
unless FMOD.type?(type, Class) && type < Dsp
|
|
231
|
+
raise TypeError, "#{type} must either be or inherit from #{Dsp}."
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
if type.is_a?(Integer)
|
|
235
|
+
klass = Dsp.type_map(type)
|
|
236
|
+
else type.is_a?(Class)
|
|
237
|
+
klass = type
|
|
238
|
+
type = Dsp.type_map(type)
|
|
239
|
+
end
|
|
240
|
+
dsp = int_ptr
|
|
241
|
+
FMOD.invoke(:System_CreateDSPByType, self, type, dsp)
|
|
242
|
+
klass.new(dsp)
|
|
243
|
+
end
|
|
244
|
+
|
|
245
|
+
##
|
|
246
|
+
# Creates a sound group, which can store handles to multiple {Sound}
|
|
247
|
+
# objects.
|
|
248
|
+
# @param name [String] Name of sound group.
|
|
249
|
+
# @return [SoundGroup] the created {SoundGroup}.
|
|
250
|
+
def create_sound_group(name)
|
|
251
|
+
utf8 = name.encode('UTF-8')
|
|
252
|
+
group = int_ptr
|
|
253
|
+
FMOD.invoke(:System_CreateSoundGroup, self, utf8, group)
|
|
254
|
+
SoundGroup.new(group)
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
##
|
|
258
|
+
# Geometry creation function. This function will create a base geometry
|
|
259
|
+
# object which can then have polygons added to it.
|
|
260
|
+
#
|
|
261
|
+
# Polygons can be added to a geometry object using {Geometry.add_polygon}.
|
|
262
|
+
#
|
|
263
|
+
# A geometry object stores its list of polygons in a structure optimized for
|
|
264
|
+
# quick line intersection testing and efficient insertion and updating. The
|
|
265
|
+
# structure works best with regularly shaped polygons with minimal overlap.
|
|
266
|
+
# Many overlapping polygons, or clusters of long thin polygons may not be
|
|
267
|
+
# handled efficiently. Axis aligned polygons are handled most efficiently.
|
|
268
|
+
#
|
|
269
|
+
# The same type of structure is used to optimize line intersection testing
|
|
270
|
+
# with multiple geometry objects.
|
|
271
|
+
#
|
|
272
|
+
# It is important to set the value of max world-size to an appropriate value
|
|
273
|
+
# using {#world_size}. Objects or polygons outside the range of max
|
|
274
|
+
# world-size will not be handled efficiently. Conversely, if max world-size
|
|
275
|
+
# is excessively large, the structure may lose precision and efficiency may
|
|
276
|
+
# drop.
|
|
277
|
+
#
|
|
278
|
+
# @param max_polygons [Integer] Maximum number of polygons within this
|
|
279
|
+
# object.
|
|
280
|
+
# @param max_vertices [Integer] Maximum number of vertices within this
|
|
281
|
+
# object.
|
|
282
|
+
def create_geometry(max_polygons, max_vertices)
|
|
283
|
+
geometry = int_ptr
|
|
284
|
+
FMOD.invoke(:System_CreateGeometry, self, max_polygons, max_vertices, geometry)
|
|
285
|
+
Geometry.new(geometry)
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
##
|
|
289
|
+
# Creates a "virtual reverb" object. This object reacts to 3D location and
|
|
290
|
+
# morphs the reverb environment based on how close it is to the reverb
|
|
291
|
+
# object's center.
|
|
292
|
+
#
|
|
293
|
+
# Multiple reverb objects can be created to achieve a multi-reverb
|
|
294
|
+
# environment. 1 Physical reverb object is used for all 3D reverb objects
|
|
295
|
+
# (slot 0 by default).
|
|
296
|
+
#
|
|
297
|
+
# The 3D reverb object is a sphere having 3D attributes (position, minimum
|
|
298
|
+
# distance, maximum distance) and reverb properties. The properties and 3D
|
|
299
|
+
# attributes of all reverb objects collectively determine, along with the
|
|
300
|
+
# listener's position, the settings of and input gains into a single 3D
|
|
301
|
+
# reverb DSP. When the listener is within the sphere of effect of one or
|
|
302
|
+
# more 3D reverbs, the listener's 3D reverb properties are a weighted
|
|
303
|
+
# combination of such 3D reverbs. When the listener is outside all of the
|
|
304
|
+
# reverbs, no reverb is applied.
|
|
305
|
+
#
|
|
306
|
+
# Creating multiple reverb objects does not impact performance. These are
|
|
307
|
+
# "virtual reverbs". There will still be only 1 physical reverb DSP running
|
|
308
|
+
# that just morphs between the different virtual reverbs.
|
|
309
|
+
#
|
|
310
|
+
# @return [Reverb3D] the created {Reverb3D} object.
|
|
311
|
+
def create_reverb
|
|
312
|
+
reverb = int_ptr
|
|
313
|
+
FMOD.invoke(:System_CreateReverb3D, self, reverb)
|
|
314
|
+
Reverb3D.new(reverb)
|
|
315
|
+
end
|
|
316
|
+
|
|
317
|
+
##
|
|
318
|
+
# Creates a {ChannelGroup} object. These objects can be used to assign
|
|
319
|
+
# channels to for group channel settings, such as volume.
|
|
320
|
+
#
|
|
321
|
+
# Channel groups are also used for sub-mixing. Any channels that are
|
|
322
|
+
# assigned to a channel group get sub-mixed into that channel group's DSP.
|
|
323
|
+
#
|
|
324
|
+
# @param name [String, nil] Optional label to give to the channel group for
|
|
325
|
+
# identification purposes.
|
|
326
|
+
# @return [ChannelGroup] the created {ChannelGroup} object.
|
|
327
|
+
def create_channel_group(name = nil)
|
|
328
|
+
FMOD.invoke(:System_CreateChannelGroup, self, name, group = int_ptr)
|
|
329
|
+
ChannelGroup.new(group)
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
##
|
|
333
|
+
# Creates a {Geometry} object that was previously serialized with
|
|
334
|
+
# {Geometry.save}.
|
|
335
|
+
# @param source [String] Either a filename where object is saved, or a
|
|
336
|
+
# binary block of serialized data.
|
|
337
|
+
# @param filename [Boolean] +true+ if source is a filename to be loaded,
|
|
338
|
+
# otherwise +false+ and source will be handled as binary data.
|
|
339
|
+
# @return [Geometry]
|
|
340
|
+
# @see Geometry.save
|
|
341
|
+
def load_geometry(source, filename = true)
|
|
342
|
+
source = IO.open(source, 'rb') { |io| io.read } if filename
|
|
343
|
+
size = source.bytesize
|
|
344
|
+
FMOD.invoke(:System_LoadGeometry, self, source, size, geometry = int_ptr)
|
|
345
|
+
Geometry.new(geometry)
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
# @!endgroup
|
|
349
|
+
|
|
350
|
+
# @!group System Resources
|
|
351
|
+
|
|
352
|
+
##
|
|
353
|
+
# Retrieves in percent of CPU time - the amount of CPU usage that FMOD is
|
|
354
|
+
# taking for streaming/mixing and {#update} combined.
|
|
355
|
+
#
|
|
356
|
+
# @return [CpuUsage] the current CPU resource usage at the time of the call.
|
|
357
|
+
def cpu_usage
|
|
358
|
+
args = ["\0" * SIZEOF_FLOAT, "\0" * SIZEOF_FLOAT, "\0" * SIZEOF_FLOAT,
|
|
359
|
+
"\0" * SIZEOF_FLOAT, "\0" * SIZEOF_FLOAT]
|
|
360
|
+
FMOD.invoke(:System_GetCPUUsage, self, *args)
|
|
361
|
+
CpuUsage.new(*args.map { |arg| arg.unpack1('f') })
|
|
362
|
+
end
|
|
363
|
+
|
|
364
|
+
##
|
|
365
|
+
# Retrieves the amount of dedicated sound ram available if the platform
|
|
366
|
+
# supports it.
|
|
367
|
+
#
|
|
368
|
+
# Most platforms use main RAM to store audio data, so this function usually
|
|
369
|
+
# isn't necessary.
|
|
370
|
+
#
|
|
371
|
+
# @return [RamUsage] the current RAM resource usage at the time of the call.
|
|
372
|
+
def ram_usage
|
|
373
|
+
args = ["\0" * SIZEOF_INT, "\0" * SIZEOF_INT, "\0" * SIZEOF_INT]
|
|
374
|
+
FMOD.invoke(:System_GetSoundRAM, self, *args)
|
|
375
|
+
RamUsage.new(*args.map { |arg| arg.unpack1('l') })
|
|
376
|
+
end
|
|
377
|
+
|
|
378
|
+
##
|
|
379
|
+
# Retrieves information about file reads by FMOD.
|
|
380
|
+
#
|
|
381
|
+
# The values returned are running totals that never reset.
|
|
382
|
+
#
|
|
383
|
+
# @return [FileUsage] the current total of file read resources used by FMOD
|
|
384
|
+
# at the time of the call.
|
|
385
|
+
def file_usage
|
|
386
|
+
args = ["\0" * SIZEOF_LONG_LONG, "\0" * SIZEOF_LONG_LONG,
|
|
387
|
+
"\0" * SIZEOF_LONG_LONG]
|
|
388
|
+
FMOD.invoke(:System_GetFileUsage, self, *args)
|
|
389
|
+
FileUsage.new(*args.map { |arg| arg.unpack1('q') })
|
|
390
|
+
end
|
|
391
|
+
|
|
392
|
+
# @!endgroup
|
|
393
|
+
|
|
394
|
+
# @!group Recording
|
|
395
|
+
|
|
396
|
+
##
|
|
397
|
+
# Stops the recording engine from recording to the specified recording
|
|
398
|
+
# sound.
|
|
399
|
+
#
|
|
400
|
+
# This does +NOT+ raise an error if a the specified driver ID is incorrect
|
|
401
|
+
# or it is not recording.
|
|
402
|
+
#
|
|
403
|
+
# @param driver_id [Integer] Enumerated driver ID.
|
|
404
|
+
#
|
|
405
|
+
# @return [void]
|
|
406
|
+
def stop_recording(driver_id)
|
|
407
|
+
FMOD.invoke(:System_RecordStop, self, driver_id)
|
|
408
|
+
end
|
|
409
|
+
|
|
410
|
+
##
|
|
411
|
+
# Starts the recording engine recording to the specified recording sound.
|
|
412
|
+
#
|
|
413
|
+
# @note The specified sound must be created with {Mode::CREATE_SAMPLE} flag.
|
|
414
|
+
#
|
|
415
|
+
# @param driver_id [Integer] Enumerated driver ID.
|
|
416
|
+
# @param sound [Sound] User created sound for the user to record to.
|
|
417
|
+
# @param loop [Boolean] Flag to tell the recording engine whether to
|
|
418
|
+
# continue recording to the provided sound from the start again, after it
|
|
419
|
+
# has reached the end. If this is set to true the data will be continually
|
|
420
|
+
# be overwritten once every loop.
|
|
421
|
+
#
|
|
422
|
+
# @return [void]
|
|
423
|
+
def record_start(driver_id, sound, loop = false)
|
|
424
|
+
FMOD.type?(sound, Sound)
|
|
425
|
+
FMOD.invoke(:System_RecordStart, self, driver_id, sound, loop.to_i)
|
|
426
|
+
end
|
|
427
|
+
|
|
428
|
+
##
|
|
429
|
+
# Retrieves the state of the FMOD recording API, ie if it is currently
|
|
430
|
+
# recording or not.
|
|
431
|
+
#
|
|
432
|
+
# @param driver_id [Integer] Enumerated driver ID.
|
|
433
|
+
#
|
|
434
|
+
# @return [Boolean] the current recording state of the specified driver.
|
|
435
|
+
def recording?(driver_id)
|
|
436
|
+
bool = "\0" * SIZEOF_INT
|
|
437
|
+
FMOD.invoke(:System_IsRecording, self, driver_id, bool)
|
|
438
|
+
bool.unpack1('l') != 0
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
##
|
|
442
|
+
# Retrieves the current recording position of the record buffer in PCM
|
|
443
|
+
# samples.
|
|
444
|
+
#
|
|
445
|
+
# @param driver_id [Integer] Enumerated driver ID.
|
|
446
|
+
#
|
|
447
|
+
# @return [Integer] the current recording position in PCM samples.
|
|
448
|
+
def record_position(driver_id)
|
|
449
|
+
position = "\0" * SIZEOF_INT
|
|
450
|
+
FMOD.invoke(:System_GetRecordPosition, self, driver_id, position)
|
|
451
|
+
position.unpack1('L')
|
|
452
|
+
end
|
|
453
|
+
|
|
454
|
+
##
|
|
455
|
+
# Retrieves the number of recording devices available for this output mode.
|
|
456
|
+
#
|
|
457
|
+
# Use this to enumerate all recording devices possible so that the user can
|
|
458
|
+
# select one.
|
|
459
|
+
#
|
|
460
|
+
# @param connected [Boolean]
|
|
461
|
+
# * *true:* Retrieve the number of recording drivers currently plugged in.
|
|
462
|
+
# * *false:* Receives the number of recording drivers available for this
|
|
463
|
+
# output mode.
|
|
464
|
+
#
|
|
465
|
+
# @return [Integer] the number of record drivers.
|
|
466
|
+
def record_driver_count(connected = true)
|
|
467
|
+
total, present = "\0" * SIZEOF_INT, "\0" * SIZEOF_INT
|
|
468
|
+
FMOD.invoke(:System_GetRecordNumDrivers, self, total, present)
|
|
469
|
+
(connected ? present : total).unpack1('l')
|
|
470
|
+
end
|
|
471
|
+
|
|
472
|
+
##
|
|
473
|
+
# Retrieves identification information about a sound device specified by its
|
|
474
|
+
# index, and specific to the output mode set with {#output}.
|
|
475
|
+
#
|
|
476
|
+
# @param id [Integer] Index of the sound driver device. The total number of
|
|
477
|
+
# devices can be found with {#record_driver_count}.
|
|
478
|
+
#
|
|
479
|
+
# @return [Driver] the specified driver information.
|
|
480
|
+
def record_driver(id)
|
|
481
|
+
args = [id, "\0" * 512, 512, Guid.new] + (0...4).map { "\0" * SIZEOF_INT }
|
|
482
|
+
FMOD.invoke(:System_GetRecordDriverInfo, self, *args)
|
|
483
|
+
Driver.send(:new, args)
|
|
484
|
+
end
|
|
485
|
+
|
|
486
|
+
##
|
|
487
|
+
# @!attribute [r] record_drivers
|
|
488
|
+
# @return [Array<Driver>] the array of available record drivers.
|
|
489
|
+
def record_drivers(connected = true)
|
|
490
|
+
(0...record_driver_count(connected)).map { |i| record_driver(i) }
|
|
491
|
+
end
|
|
492
|
+
|
|
493
|
+
# @!endgroup
|
|
494
|
+
|
|
495
|
+
# @!group Sound Card Drivers
|
|
496
|
+
|
|
497
|
+
##
|
|
498
|
+
# @!attribute output
|
|
499
|
+
# The output mode for the platform. This is for selecting different OS
|
|
500
|
+
# specific APIs which might have different features.
|
|
501
|
+
#
|
|
502
|
+
# Changing this is only necessary if you want to specifically switch away
|
|
503
|
+
# from the default output mode for the operating system. The most optimal
|
|
504
|
+
# mode is selected by default for the operating system.
|
|
505
|
+
#
|
|
506
|
+
# @see OutputMode
|
|
507
|
+
# @return [Integer] the output mode for the platform.
|
|
508
|
+
integer_reader(:output, :System_GetOutput)
|
|
509
|
+
integer_writer(:output=, :System_SetOutput)
|
|
510
|
+
|
|
511
|
+
##
|
|
512
|
+
# @!attribute [r] driver_count
|
|
513
|
+
# @return [Integer] the number of sound-card devices on the machine,
|
|
514
|
+
# specific to the output mode set with {#output}.
|
|
515
|
+
integer_reader(:driver_count, :System_GetNumDrivers)
|
|
516
|
+
|
|
517
|
+
##
|
|
518
|
+
# @!attribute current_driver
|
|
519
|
+
# @return [Integer] the currently selected driver number. 0 represents the
|
|
520
|
+
# primary or default driver.
|
|
521
|
+
integer_reader(:current_driver, :System_GetDriver)
|
|
522
|
+
integer_writer(:current_driver=, :System_SetDriver)
|
|
523
|
+
|
|
524
|
+
##
|
|
525
|
+
# Retrieves identification information about a sound device specified by its
|
|
526
|
+
# index, and specific to the output mode set with {#output}.
|
|
527
|
+
#
|
|
528
|
+
# @param id [Integer] Index of the sound driver device. The total number of
|
|
529
|
+
# devices can be found with {#driver_count}.
|
|
530
|
+
#
|
|
531
|
+
# @return [Driver] the driver information.
|
|
532
|
+
def driver_info(id)
|
|
533
|
+
args = [id, "\0" * 512, 512, Guid.new] + (0...3).map { "\0" * SIZEOF_INT }
|
|
534
|
+
FMOD.invoke(:System_GetDriverInfo, self, *args)
|
|
535
|
+
Driver.send(:new, args)
|
|
536
|
+
end
|
|
537
|
+
|
|
538
|
+
##
|
|
539
|
+
# @!attribute output_handle
|
|
540
|
+
# Retrieves a pointer to the system level output device module. This means a
|
|
541
|
+
# pointer to a DirectX "LPDIRECTSOUND", or a WINMM handle, or with something
|
|
542
|
+
# like with {OutputType::NO_SOUND} output, the handle will be {FMOD::NULL}.
|
|
543
|
+
#
|
|
544
|
+
# @return [Pointer] the handle to the output mode's native hardware API
|
|
545
|
+
# object.
|
|
546
|
+
def output_handle
|
|
547
|
+
FMOD.invoke(:System_GetOutputHandle, self, handle = int_ptr)
|
|
548
|
+
Pointer.new(handle.unpack1('J'))
|
|
549
|
+
end
|
|
550
|
+
|
|
551
|
+
##
|
|
552
|
+
# @!attribute [r] drivers
|
|
553
|
+
# @return [Array<Driver>] the array of available drivers.
|
|
554
|
+
def drivers
|
|
555
|
+
(0...driver_count).map { |id| driver_info(id) }
|
|
556
|
+
end
|
|
557
|
+
|
|
558
|
+
# @!endgroup
|
|
559
|
+
|
|
560
|
+
# @!group 3D Sound
|
|
561
|
+
|
|
562
|
+
##
|
|
563
|
+
# @!attribute doppler_scale
|
|
564
|
+
# The general scaling factor for how much the pitch varies due to doppler
|
|
565
|
+
# shifting in 3D sound.
|
|
566
|
+
#
|
|
567
|
+
# Doppler is the pitch bending effect when a sound comes towards the
|
|
568
|
+
# listener or moves away from it, much like the effect you hear when a train
|
|
569
|
+
# goes past you with its horn sounding. With "doppler scale" you can
|
|
570
|
+
# exaggerate or diminish the effect. FMOD's effective speed of sound at a
|
|
571
|
+
# doppler factor of 1.0 is 340 m/s.
|
|
572
|
+
#
|
|
573
|
+
# @return [Float] the scaling factor.
|
|
574
|
+
|
|
575
|
+
def doppler_scale
|
|
576
|
+
scale = "\0" * SIZEOF_FLOAT
|
|
577
|
+
FMOD.invoke(:System_Get3DSettings, self, scale, nil, nil)
|
|
578
|
+
scale.unpack1('f')
|
|
579
|
+
end
|
|
580
|
+
|
|
581
|
+
def doppler_scale=(scale)
|
|
582
|
+
FMOD.invoke(:System_Set3DSettings, self, scale,
|
|
583
|
+
distance_factor, rolloff_scale)
|
|
584
|
+
end
|
|
585
|
+
|
|
586
|
+
##
|
|
587
|
+
# @!attribute distance_factor
|
|
588
|
+
# The FMOD 3D engine relative distance factor, compared to 1.0 meters.
|
|
589
|
+
#
|
|
590
|
+
# Another way to put it is that it equates to "how many units per meter does
|
|
591
|
+
# your engine have". For example, if you are using feet then "scale" would
|
|
592
|
+
# equal 3.28.
|
|
593
|
+
#
|
|
594
|
+
# @return [Float] the relative distance factor.
|
|
595
|
+
|
|
596
|
+
def distance_factor
|
|
597
|
+
factor = "\0" * SIZEOF_FLOAT
|
|
598
|
+
FMOD.invoke(:System_Get3DSettings, self, nil, factor, nil)
|
|
599
|
+
factor.unpack1('f')
|
|
600
|
+
end
|
|
601
|
+
|
|
602
|
+
def distance_factor=(factor)
|
|
603
|
+
FMOD.invoke(:System_Set3DSettings, self, doppler_scale,
|
|
604
|
+
factor, rolloff_scale)
|
|
605
|
+
end
|
|
606
|
+
|
|
607
|
+
##
|
|
608
|
+
# @!attribute rolloff_scale
|
|
609
|
+
# The global attenuation rolloff factor for {Mode::INVERSE_ROLLOFF_3D} based
|
|
610
|
+
# sounds only (which is the default).
|
|
611
|
+
#
|
|
612
|
+
# Volume for a sound set to {Mode::INVERSE_ROLLOFF_3D} will scale at minimum
|
|
613
|
+
# distance / distance. This gives an inverse attenuation of volume as the
|
|
614
|
+
# source gets further away (or closer). Setting this value makes the sound
|
|
615
|
+
# drop off faster or slower. The higher the value, the faster volume will
|
|
616
|
+
# attenuate, and conversely the lower the value, the slower it will
|
|
617
|
+
# attenuate. For example a rolloff factor of 1 will simulate the real world,
|
|
618
|
+
# where as a value of 2 will make sounds attenuate 2 times quicker.
|
|
619
|
+
#
|
|
620
|
+
# @return [Float] the global rolloff factor.
|
|
621
|
+
|
|
622
|
+
def rolloff_scale
|
|
623
|
+
scale = "\0" * SIZEOF_FLOAT
|
|
624
|
+
FMOD.invoke(:System_Get3DSettings, self, nil, nil, scale)
|
|
625
|
+
scale.unpack1('f')
|
|
626
|
+
end
|
|
627
|
+
|
|
628
|
+
def rolloff_scale=(scale)
|
|
629
|
+
FMOD.invoke(:System_Set3DSettings, self, doppler_scale,
|
|
630
|
+
distance_factor, scale)
|
|
631
|
+
end
|
|
632
|
+
|
|
633
|
+
##
|
|
634
|
+
# Calculates geometry occlusion between a listener and a sound source.
|
|
635
|
+
#
|
|
636
|
+
# @param listener [Vector] The listener position.
|
|
637
|
+
# @param source [Vector] The source position.
|
|
638
|
+
#
|
|
639
|
+
# @return [Array(Float, Float)] the occlusion values as an array, the first
|
|
640
|
+
# element being the direct occlusion value, and the second element being
|
|
641
|
+
# the reverb occlusion value.
|
|
642
|
+
def geometry_occlusion(listener, source)
|
|
643
|
+
FMOD.type?(listener, Vector)
|
|
644
|
+
FMOD.type?(source, Vector)
|
|
645
|
+
args = ["\0" * SIZEOF_FLOAT, "\0" * SIZEOF_FLOAT]
|
|
646
|
+
FMOD.invoke(:System_GetGeometryOcclusion, self, listener, source, *args)
|
|
647
|
+
args.join.unpack('ff')
|
|
648
|
+
end
|
|
649
|
+
|
|
650
|
+
##
|
|
651
|
+
# @!attribute listeners
|
|
652
|
+
# The number of 3D "listeners" in the 3D sound scene. This is useful mainly
|
|
653
|
+
# for split-screen game purposes.
|
|
654
|
+
#
|
|
655
|
+
# If the number of listeners is set to more than 1, then panning and doppler
|
|
656
|
+
# are turned off. *All* sound effects will be mono. FMOD uses a "closest
|
|
657
|
+
# sound to the listener" method to determine what should be heard in this
|
|
658
|
+
# case.
|
|
659
|
+
# * *Minimum:* 1
|
|
660
|
+
# * *Maximum:* {FMOD::MAX_LISTENERS}
|
|
661
|
+
# * *Default:* 1
|
|
662
|
+
# @return [Integer]
|
|
663
|
+
integer_reader(:listeners, :System_Get3DNumListeners)
|
|
664
|
+
integer_writer(:listeners=, :System_Set3DNumListeners, 1, FMOD::MAX_LISTENERS)
|
|
665
|
+
|
|
666
|
+
##
|
|
667
|
+
# @!attribute world_size
|
|
668
|
+
# The maximum world size for the geometry engine for performance / precision
|
|
669
|
+
# reasons
|
|
670
|
+
#
|
|
671
|
+
# This setting should be done first before creating any geometry.
|
|
672
|
+
# It can be done any time afterwards but may be slow in this case.
|
|
673
|
+
#
|
|
674
|
+
# Objects or polygons outside the range of this value will not be handled
|
|
675
|
+
# efficiently. Conversely, if this value is excessively large, the structure
|
|
676
|
+
# may loose precision and efficiency may drop.
|
|
677
|
+
#
|
|
678
|
+
# @return [Float] the maximum world size for the geometry engine.
|
|
679
|
+
float_reader(:world_size, :System_GetGeometrySettings)
|
|
680
|
+
float_writer(:world_size=, :System_SetGeometrySettings)
|
|
681
|
+
|
|
682
|
+
# @!endgroup
|
|
683
|
+
|
|
684
|
+
# @!group Plugin Support
|
|
685
|
+
|
|
686
|
+
##
|
|
687
|
+
# Loads an FMOD plugin. This could be a DSP, file format or output plugin.
|
|
688
|
+
#
|
|
689
|
+
# @param filename [String] Filename of the plugin to be loaded.
|
|
690
|
+
# @param priority [Integer] Codec plugins only, priority of the codec
|
|
691
|
+
# compared to other codecs, where 0 is the most important and higher
|
|
692
|
+
# numbers are less important.
|
|
693
|
+
#
|
|
694
|
+
# @return [Integer] the handle to the plugin.
|
|
695
|
+
def load_plugin(filename, priority = 128)
|
|
696
|
+
# noinspection RubyResolve
|
|
697
|
+
path = filename.encode(Encoding::UTF_8)
|
|
698
|
+
handle = "\0" * SIZEOF_INT
|
|
699
|
+
FMOD.invoke(:System_LoadPlugin, self, path, handle, priority)
|
|
700
|
+
handle.unpack1('L')
|
|
701
|
+
end
|
|
702
|
+
|
|
703
|
+
##
|
|
704
|
+
# Unloads a plugin from memory.
|
|
705
|
+
#
|
|
706
|
+
# @param handle [Integer] Handle to a pre-existing plugin.
|
|
707
|
+
#
|
|
708
|
+
# @return [void]
|
|
709
|
+
def unload_plugin(handle)
|
|
710
|
+
FMOD.invoke(:System_UnloadPlugin, self, handle)
|
|
711
|
+
end
|
|
712
|
+
|
|
713
|
+
##
|
|
714
|
+
# Retrieves the number of available plugins loaded into FMOD at the current
|
|
715
|
+
# time.
|
|
716
|
+
#
|
|
717
|
+
# @param type [Symbol] Specifies the type of plugin(s) to enumerate.
|
|
718
|
+
# * <b>:output</b> The plugin type is an output module. FMOD mixed audio
|
|
719
|
+
# will play through one of these devices
|
|
720
|
+
# * <b>:codec</b> The plugin type is a file format codec. FMOD will use
|
|
721
|
+
# these codecs to load file formats for playback.
|
|
722
|
+
# * <b>:dsp</b> The plugin type is a DSP unit. FMOD will use these plugins
|
|
723
|
+
# as part of its DSP network to apply effects to output or generate.rb
|
|
724
|
+
# sound in realtime.
|
|
725
|
+
# @return [Integer] the plugin count.
|
|
726
|
+
def plugin_count(type = :all)
|
|
727
|
+
plugin_type = %i[output codec dsp].index(type)
|
|
728
|
+
count = "\0" * SIZEOF_INT
|
|
729
|
+
unless plugin_type.nil?
|
|
730
|
+
FMOD.invoke(:System_GetNumPlugins, self, plugin_type, count)
|
|
731
|
+
return count.unpack1('l')
|
|
732
|
+
end
|
|
733
|
+
total = 0
|
|
734
|
+
(0..2).each do |i|
|
|
735
|
+
FMOD.invoke(:System_GetNumPlugins, self, i, count)
|
|
736
|
+
total += count.unpack1('l')
|
|
737
|
+
end
|
|
738
|
+
total
|
|
739
|
+
end
|
|
740
|
+
|
|
741
|
+
##
|
|
742
|
+
# Specify a base search path for plugins so they can be placed somewhere
|
|
743
|
+
# else than the directory of the main executable.
|
|
744
|
+
#
|
|
745
|
+
# @param directory [String] A string containing a correctly formatted path
|
|
746
|
+
# to load plugins from.
|
|
747
|
+
#
|
|
748
|
+
# @return [void]
|
|
749
|
+
def plugin_path(directory)
|
|
750
|
+
# noinspection RubyResolve
|
|
751
|
+
path = directory.encode(Encoding::UTF_8)
|
|
752
|
+
FMOD.invoke(:System_SetPluginPath, self, path)
|
|
753
|
+
end
|
|
754
|
+
|
|
755
|
+
##
|
|
756
|
+
# Retrieves the handle of a plugin based on its type and relative index.
|
|
757
|
+
#
|
|
758
|
+
# @param type [Symbol] The type of plugin type.
|
|
759
|
+
# * <b>:output</b> The plugin type is an output module. FMOD mixed audio
|
|
760
|
+
# will play through one of these devices
|
|
761
|
+
# * <b>:codec</b> The plugin type is a file format codec. FMOD will use
|
|
762
|
+
# these codecs to load file formats for playback.
|
|
763
|
+
# * <b>:dsp</b> The plugin type is a DSP unit. FMOD will use these plugins
|
|
764
|
+
# as part of its DSP network to apply effects to output or generate.rb
|
|
765
|
+
# sound in realtime.
|
|
766
|
+
# @param index [Integer] The relative index for the type of plugin.
|
|
767
|
+
#
|
|
768
|
+
# @return [Integer] the handle to the plugin.
|
|
769
|
+
def plugin(type, index)
|
|
770
|
+
handle = "\0" * SIZEOF_INT
|
|
771
|
+
plugin_type = %i[output codec dsp].index(type)
|
|
772
|
+
raise ArgumentError, "Invalid plugin type: #{type}." if plugin_type.nil?
|
|
773
|
+
FMOD.invoke(:System_GetPluginHandle, self, plugin_type, index, handle)
|
|
774
|
+
handle.unpack1('L')
|
|
775
|
+
end
|
|
776
|
+
|
|
777
|
+
##
|
|
778
|
+
# Returns nested plugin definition for the given index.
|
|
779
|
+
#
|
|
780
|
+
# For plugins consisting of a single definition, only index 0 is valid and
|
|
781
|
+
# the returned handle is the same as the handle passed in.
|
|
782
|
+
#
|
|
783
|
+
# @param handle [Integer] A handle to an existing plugin returned from
|
|
784
|
+
# {#load_plugin}.
|
|
785
|
+
# @param index [Integer] Index into the list of plugin definitions.
|
|
786
|
+
#
|
|
787
|
+
# @return [Integer] the handle to the nested plugin.
|
|
788
|
+
def nested_plugin(handle, index)
|
|
789
|
+
nested = "\0" * SIZEOF_INT
|
|
790
|
+
FMOD.invoke(:System_GetNestedPlugin, self, handle, index, nested)
|
|
791
|
+
nested.unpack1('L')
|
|
792
|
+
end
|
|
793
|
+
|
|
794
|
+
##
|
|
795
|
+
# Returns the number of plugins nested in the one plugin file.
|
|
796
|
+
#
|
|
797
|
+
# Plugins normally have a single definition in them, in which case the count
|
|
798
|
+
# is always 1.
|
|
799
|
+
#
|
|
800
|
+
# For plugins that have a list of definitions, this function returns the
|
|
801
|
+
# number of plugins that have been defined. {#nested_plugin} can be used to
|
|
802
|
+
# find each handle.
|
|
803
|
+
#
|
|
804
|
+
# @param handle [Integer] A handle to an existing plugin returned from
|
|
805
|
+
# {#load_plugin}.
|
|
806
|
+
#
|
|
807
|
+
# @return [Integer] the number of nested plugins.
|
|
808
|
+
def nested_plugin_count(handle)
|
|
809
|
+
count = "\0" * SIZEOF_INT
|
|
810
|
+
FMOD.invoke(:System_GetNumNestedPlugins, self, handle, count)
|
|
811
|
+
count.unpack1('l')
|
|
812
|
+
end
|
|
813
|
+
|
|
814
|
+
##
|
|
815
|
+
# Retrieves information to display for the selected plugin.
|
|
816
|
+
#
|
|
817
|
+
# @param handle [Integer] The handle to the plugin.
|
|
818
|
+
#
|
|
819
|
+
# @return [Plugin] the plugin information.
|
|
820
|
+
def plugin_info(handle)
|
|
821
|
+
name, type, vs = "\0" * 512, "\0" * SIZEOF_INT, "\0" * SIZEOF_INT
|
|
822
|
+
FMOD.invoke(:System_GetPluginInfo, self, handle, type, name, 512, vs)
|
|
823
|
+
type = %i[output codec dsp][type.unpack1('l')]
|
|
824
|
+
# noinspection RubyResolve
|
|
825
|
+
name = name.delete("\0").force_encoding(Encoding::UTF_8)
|
|
826
|
+
Plugin.new(handle, type, name, FMOD.uint2version(vs))
|
|
827
|
+
end
|
|
828
|
+
|
|
829
|
+
##
|
|
830
|
+
# @!attribute plugin_output
|
|
831
|
+
# @return [Integer] the currently selected output as an ID in the list of
|
|
832
|
+
# output plugins.
|
|
833
|
+
integer_reader(:plugin_output, :System_GetOutputByPlugin)
|
|
834
|
+
integer_writer(:plugin_output=, :System_SetOutputByPlugin)
|
|
835
|
+
|
|
836
|
+
##
|
|
837
|
+
# @param handle [Integer] Handle to a pre-existing DSP plugin.
|
|
838
|
+
# @return [DspDescription] the description structure for a pre-existing DSP
|
|
839
|
+
# plugin.
|
|
840
|
+
def plugin_dsp_info(handle)
|
|
841
|
+
FMOD.invoke(:System_GetDSPInfoByPlugin, self, handle, address = int_ptr)
|
|
842
|
+
DspDescription.new(address)
|
|
843
|
+
end
|
|
844
|
+
|
|
845
|
+
##
|
|
846
|
+
# Enumerates the loaded plugins, optionally specifying the type of plugins
|
|
847
|
+
# to loop through.
|
|
848
|
+
#
|
|
849
|
+
# @overload each_plugin(plugin_type = :all)
|
|
850
|
+
# When a block is passed, yields each plugin to the block in turn before
|
|
851
|
+
# returning self.
|
|
852
|
+
# @yield [plugin] Yields a plugin to the block.
|
|
853
|
+
# @yieldparam plugin [Plugin] The currently enumerated plugin.
|
|
854
|
+
# @return [self]
|
|
855
|
+
# @overload each_plugin(plugin_type = :all)
|
|
856
|
+
# When no block is given, returns an enumerator for the plugins.
|
|
857
|
+
# @return [Enumerator]
|
|
858
|
+
# @param plugin_type [Symbol] Specifies the type of plugin(s) to enumerate.
|
|
859
|
+
# * <b>:output</b> The plugin type is an output module. FMOD mixed audio
|
|
860
|
+
# will play through one of these devices
|
|
861
|
+
# * <b>:codec</b> The plugin type is a file format codec. FMOD will use
|
|
862
|
+
# these codecs to load file formats for playback.
|
|
863
|
+
# * <b>:dsp</b> The plugin type is a DSP unit. FMOD will use these plugins
|
|
864
|
+
# as part of its DSP network to apply effects to output or generate.rb
|
|
865
|
+
# sound in realtime.
|
|
866
|
+
def each_plugin(plugin_type = :all)
|
|
867
|
+
return to_enum(:each_plugin) unless block_given?
|
|
868
|
+
types = plugin_type == :all ? %i[output codec dsp] : [plugin_type]
|
|
869
|
+
types.each do |type|
|
|
870
|
+
(0...plugin_count(type)).each do |index|
|
|
871
|
+
handle = plugin(type, index)
|
|
872
|
+
yield plugin_info(handle)
|
|
873
|
+
end
|
|
874
|
+
end
|
|
875
|
+
self
|
|
876
|
+
end
|
|
877
|
+
|
|
878
|
+
# @!endgroup
|
|
879
|
+
|
|
880
|
+
|
|
881
|
+
|
|
882
|
+
|
|
883
|
+
|
|
884
|
+
|
|
885
|
+
|
|
886
|
+
|
|
887
|
+
|
|
888
|
+
|
|
889
|
+
|
|
890
|
+
|
|
891
|
+
|
|
892
|
+
|
|
893
|
+
|
|
894
|
+
|
|
895
|
+
|
|
896
|
+
|
|
897
|
+
|
|
898
|
+
|
|
899
|
+
|
|
900
|
+
|
|
901
|
+
|
|
902
|
+
|
|
903
|
+
|
|
904
|
+
|
|
905
|
+
|
|
906
|
+
|
|
907
|
+
|
|
908
|
+
|
|
909
|
+
|
|
910
|
+
|
|
911
|
+
|
|
912
|
+
|
|
913
|
+
|
|
914
|
+
|
|
915
|
+
|
|
916
|
+
def network_proxy
|
|
917
|
+
buffer = "\0" * 512
|
|
918
|
+
FMOD.invoke(:System_GetNetworkProxy, self, buffer, 512)
|
|
919
|
+
# noinspection RubyResolve
|
|
920
|
+
buffer.delete("\0").force_encoding(Encoding::UTF_8)
|
|
921
|
+
end
|
|
922
|
+
|
|
923
|
+
def network_proxy=(url)
|
|
924
|
+
# noinspection RubyResolve
|
|
925
|
+
FMOD.invoke(:System_SetNetworkProxy, self, url.encode(Encoding::UTF_8))
|
|
926
|
+
end
|
|
927
|
+
|
|
928
|
+
integer_reader(:network_timeout, :System_GetNetworkTimeout)
|
|
929
|
+
integer_writer(:network_timeout=, :System_SetNetworkTimeout)
|
|
930
|
+
|
|
931
|
+
integer_reader(:software_channels, :System_GetSoftwareChannels)
|
|
932
|
+
integer_writer(:software_channels=, :System_SetSoftwareChannels, 0, 64)
|
|
933
|
+
|
|
934
|
+
|
|
935
|
+
|
|
936
|
+
def master_channel_group
|
|
937
|
+
FMOD.invoke(:System_GetMasterChannelGroup, self, group = int_ptr)
|
|
938
|
+
ChannelGroup.new(group)
|
|
939
|
+
end
|
|
940
|
+
|
|
941
|
+
def master_sound_group
|
|
942
|
+
FMOD.invoke(:System_GetMasterSoundGroup, self, group = int_ptr)
|
|
943
|
+
SoundGroup.new(group)
|
|
944
|
+
end
|
|
945
|
+
|
|
946
|
+
|
|
947
|
+
def update
|
|
948
|
+
FMOD.invoke(:System_Update, self)
|
|
949
|
+
end
|
|
950
|
+
|
|
951
|
+
##
|
|
952
|
+
# Closes the {System} object without freeing the object's memory, so the
|
|
953
|
+
# system handle will still be valid.
|
|
954
|
+
#
|
|
955
|
+
# Closing the output renders objects created with this system object
|
|
956
|
+
# invalid. Make sure any sounds, channel groups, geometry and DSP objects
|
|
957
|
+
# are released before closing the system object.
|
|
958
|
+
#
|
|
959
|
+
# @return [void]
|
|
960
|
+
def close
|
|
961
|
+
FMOD.invoke(:System_Close, self)
|
|
962
|
+
end
|
|
963
|
+
|
|
964
|
+
##
|
|
965
|
+
# @!attribute [r] version
|
|
966
|
+
# @return [String] the current version of FMOD being used.
|
|
967
|
+
def version
|
|
968
|
+
FMOD.invoke(:System_GetVersion, self, version = "\0" * SIZEOF_INT)
|
|
969
|
+
FMOD.uint2version(version)
|
|
970
|
+
end
|
|
971
|
+
|
|
972
|
+
##
|
|
973
|
+
# Plays a sound object on a particular channel and {ChannelGroup}.
|
|
974
|
+
#
|
|
975
|
+
# When a sound is played, it will use the sound's default frequency and
|
|
976
|
+
# priority.
|
|
977
|
+
#
|
|
978
|
+
# A sound defined as {Mode::THREE_D} will by default play at the position of
|
|
979
|
+
# the listener.
|
|
980
|
+
#
|
|
981
|
+
# Channels are reference counted. If a channel is stolen by the FMOD
|
|
982
|
+
# priority system, then the handle to the stolen voice becomes invalid, and
|
|
983
|
+
# Channel based commands will not affect the new sound playing in its place.
|
|
984
|
+
# If all channels are currently full playing a sound, FMOD will steal a
|
|
985
|
+
# channel with the lowest priority sound. If more channels are playing than
|
|
986
|
+
# are currently available on the sound-card/sound device or software mixer,
|
|
987
|
+
# then FMOD will "virtualize" the channel. This type of channel is not
|
|
988
|
+
# heard, but it is updated as if it was playing. When its priority becomes
|
|
989
|
+
# high enough or another sound stops that was using a real hardware/software
|
|
990
|
+
# channel, it will start playing from where it should be. This technique
|
|
991
|
+
# saves CPU time (thousands of sounds can be played at once without actually
|
|
992
|
+
# being mixed or taking up resources), and also removes the need for the
|
|
993
|
+
# user to manage voices themselves. An example of virtual channel usage is a
|
|
994
|
+
# dungeon with 100 torches burning, all with a looping crackling sound, but
|
|
995
|
+
# with a sound-card that only supports 32 hardware voices. If the 3D
|
|
996
|
+
# positions and priorities for each torch are set correctly, FMOD will play
|
|
997
|
+
# all 100 sounds without any 'out of channels' errors, and swap the real
|
|
998
|
+
# voices in and out according to which torches are closest in 3D space.
|
|
999
|
+
# Priority for virtual channels can be changed in the sound's defaults, or
|
|
1000
|
+
# at runtime with {Channel.priority}.
|
|
1001
|
+
#
|
|
1002
|
+
# @param sound [Sound] The sound to play.
|
|
1003
|
+
# @param group [ChannelGroup] The {ChannelGroup} become a member of. This is
|
|
1004
|
+
# more efficient than using {Channel.group}, as it does it during the
|
|
1005
|
+
# channel setup, rather than connecting to the master channel group, then
|
|
1006
|
+
# later disconnecting and connecting to the new {ChannelGroup} when
|
|
1007
|
+
# specified. Specify +nil+ to ignore (use master {ChannelGroup}).
|
|
1008
|
+
# @param paused [Boolean] flag to specify whether to start the channel
|
|
1009
|
+
# paused or not. Starting a channel paused allows the user to alter its
|
|
1010
|
+
# attributes without it being audible, and un-pausing with
|
|
1011
|
+
# ChannelControl.resume actually starts the sound.
|
|
1012
|
+
#
|
|
1013
|
+
# @return [Channel] the newly playing channel.
|
|
1014
|
+
def play_sound(sound, group = nil, paused = false)
|
|
1015
|
+
FMOD.type?(sound, Sound)
|
|
1016
|
+
channel = int_ptr
|
|
1017
|
+
FMOD.invoke(:System_PlaySound, self, sound, group, paused.to_i, channel)
|
|
1018
|
+
Channel.new(channel)
|
|
1019
|
+
end
|
|
1020
|
+
|
|
1021
|
+
def play_dsp(dsp, group = nil, paused = false)
|
|
1022
|
+
FMOD.type?(dsp, Dsp)
|
|
1023
|
+
channel = int_ptr
|
|
1024
|
+
FMOD.invoke(:System_PlayDSP, self, dsp, group, paused.to_i, channel)
|
|
1025
|
+
Channel.new(channel)
|
|
1026
|
+
end
|
|
1027
|
+
|
|
1028
|
+
def [](index)
|
|
1029
|
+
reverb = int_ptr
|
|
1030
|
+
FMOD.invoke(:System_GetReverbProperties, self, index, reverb)
|
|
1031
|
+
Reverb.new(reverb.unpack1('J'))
|
|
1032
|
+
end
|
|
1033
|
+
|
|
1034
|
+
def []=(index, reverb)
|
|
1035
|
+
FMOD.type?(reverb, Reverb)
|
|
1036
|
+
FMOD.invoke(:System_SetReverbProperties, self, index, reverb)
|
|
1037
|
+
end
|
|
1038
|
+
|
|
1039
|
+
def mixer_suspend
|
|
1040
|
+
FMOD.invoke(:System_MixerSuspend, self)
|
|
1041
|
+
if block_given?
|
|
1042
|
+
yield
|
|
1043
|
+
FMOD.invoke(:System_MixerResume, self)
|
|
1044
|
+
end
|
|
1045
|
+
end
|
|
1046
|
+
|
|
1047
|
+
def mixer_resume
|
|
1048
|
+
FMOD.invoke(:System_MixerResume, self)
|
|
1049
|
+
end
|
|
1050
|
+
|
|
1051
|
+
##
|
|
1052
|
+
# Route the signal from a channel group into a separate audio port on the
|
|
1053
|
+
# output driver.
|
|
1054
|
+
#
|
|
1055
|
+
# Note that an FMOD port is a hardware specific reference, to hardware
|
|
1056
|
+
# devices that exist on only certain platforms (like a console headset, or
|
|
1057
|
+
# dedicated hardware music channel for example). It is not supported on all
|
|
1058
|
+
# platforms.
|
|
1059
|
+
#
|
|
1060
|
+
# @param group [ChannelGroup] Channel group to route away to the new port.
|
|
1061
|
+
# @param port_type [Integer] Output driver specific audio port type. See
|
|
1062
|
+
# extra platform specific header (if it exists) for port numbers
|
|
1063
|
+
# @param port_index [Integer] Output driver specific index of the audio
|
|
1064
|
+
# port. Use {FMOD::PORT_INDEX_NONE} if this is not required.
|
|
1065
|
+
# @param pass_thru [Boolean] If +true+ the signal will continue to be passed
|
|
1066
|
+
# through to the main mix, if +false+ the signal will be entirely to the
|
|
1067
|
+
# designated port.
|
|
1068
|
+
#
|
|
1069
|
+
# @return [void]
|
|
1070
|
+
def attach_to_port(group, port_type, port_index, pass_thru)
|
|
1071
|
+
FMOD.type?(group, ChannelGroup)
|
|
1072
|
+
FMOD.invoke(:System_AttachChannelGroupToPort, self, port_type,
|
|
1073
|
+
port_index, group, pass_thru.to_i)
|
|
1074
|
+
end
|
|
1075
|
+
|
|
1076
|
+
##
|
|
1077
|
+
# Disconnect a channel group from a port and route audio back to the default
|
|
1078
|
+
# port of the output driver.
|
|
1079
|
+
#
|
|
1080
|
+
# @param group [ChannelGroup] Channel group to route away back to the
|
|
1081
|
+
# default audio port.
|
|
1082
|
+
#
|
|
1083
|
+
# @return [void]
|
|
1084
|
+
def detach_from_port(group)
|
|
1085
|
+
FMOD.type?(group, ChannelGroup)
|
|
1086
|
+
FMOD.invoke(:System_DetachChannelGroupFromPort, self, group)
|
|
1087
|
+
end
|
|
1088
|
+
|
|
1089
|
+
##
|
|
1090
|
+
# Mutual exclusion function to lock the FMOD DSP engine (which runs
|
|
1091
|
+
# asynchronously in another thread), so that it will not execute. If the
|
|
1092
|
+
# FMOD DSP engine is already executing, this function will block until it
|
|
1093
|
+
# has completed.
|
|
1094
|
+
#
|
|
1095
|
+
# The function may be used to synchronize DSP network operations carried out
|
|
1096
|
+
# by the user.
|
|
1097
|
+
#
|
|
1098
|
+
# An example of using this function may be for when the user wants to
|
|
1099
|
+
# construct a DSP sub-network, without the DSP engine executing in the
|
|
1100
|
+
# background while the sub-network is still under construction.
|
|
1101
|
+
#
|
|
1102
|
+
# Once the user no longer needs the DSP engine locked, it must be unlocked
|
|
1103
|
+
# with {#unlock_dsp}.
|
|
1104
|
+
#
|
|
1105
|
+
# Note that the DSP engine should not be locked for a significant amount of
|
|
1106
|
+
# time, otherwise inconsistency in the audio output may result. (audio
|
|
1107
|
+
# skipping/stuttering).
|
|
1108
|
+
#
|
|
1109
|
+
# @overload lock_dsp
|
|
1110
|
+
# Locks the DSP engine, must unlock with {#unlock_dsp}.
|
|
1111
|
+
# @overload lock_dsp
|
|
1112
|
+
# @yield Locks the DSP engine, and unlocks it when the block exits.
|
|
1113
|
+
# @return [void]
|
|
1114
|
+
def lock_dsp
|
|
1115
|
+
FMOD.invoke(:System_LockDSP, self)
|
|
1116
|
+
if block_given?
|
|
1117
|
+
yield
|
|
1118
|
+
FMOD.invoke(:System_UnlockDSP, self)
|
|
1119
|
+
end
|
|
1120
|
+
end
|
|
1121
|
+
|
|
1122
|
+
##
|
|
1123
|
+
# Mutual exclusion function to unlock the FMOD DSP engine (which runs
|
|
1124
|
+
# asynchronously in another thread) and let it continue executing.
|
|
1125
|
+
#
|
|
1126
|
+
# @note The DSP engine must be locked with {#lock_dsp} before this function
|
|
1127
|
+
# is called.
|
|
1128
|
+
# @return [void]
|
|
1129
|
+
def unlock_dsp
|
|
1130
|
+
FMOD.invoke(:System_UnlockDSP, self)
|
|
1131
|
+
end
|
|
1132
|
+
|
|
1133
|
+
##
|
|
1134
|
+
# Helper method to create and enumerate each type of internal DSP unit.
|
|
1135
|
+
# @overload each_dsp
|
|
1136
|
+
# When called with a block, yields each DSP type in turn before returning
|
|
1137
|
+
# self.
|
|
1138
|
+
# @yield [dsp] Yields a DSP unit to the block.
|
|
1139
|
+
# @yieldparam dsp [Dsp] The current enumerated DSP unit.
|
|
1140
|
+
# @return [self]
|
|
1141
|
+
# @overload each_dsp
|
|
1142
|
+
# When called without a block, returns an enumerator for the DSP units.
|
|
1143
|
+
# @return [Enumerator]
|
|
1144
|
+
def each_dsp
|
|
1145
|
+
return to_enum(:each_dsp) unless block_given?
|
|
1146
|
+
FMOD::DspType.constants(false).each do |const|
|
|
1147
|
+
type = DspType.const_get(const)
|
|
1148
|
+
yield create_dsp(type) rescue next
|
|
1149
|
+
end
|
|
1150
|
+
self
|
|
1151
|
+
end
|
|
1152
|
+
|
|
1153
|
+
##
|
|
1154
|
+
# Retrieves the number of currently playing channels.
|
|
1155
|
+
# @param total [Boolean] +true+ to return the number of playing channels
|
|
1156
|
+
# (both real and virtual), +false+ to return the number of playing
|
|
1157
|
+
# non-virtual channels only.
|
|
1158
|
+
# @return [Integer] the number of playing channels.
|
|
1159
|
+
def playing_channels(total = true)
|
|
1160
|
+
count, real = "\0" * SIZEOF_INT, "\0" * SIZEOF_INT
|
|
1161
|
+
FMOD.invoke(:System_GetChannelsPlaying, self, count, real)
|
|
1162
|
+
(total ? count : real).unpack1('l')
|
|
1163
|
+
end
|
|
1164
|
+
|
|
1165
|
+
##
|
|
1166
|
+
# Retrieves a handle to a channel by ID.
|
|
1167
|
+
#
|
|
1168
|
+
# @param id [Integer] Index in the FMOD channel pool. Specify a channel
|
|
1169
|
+
# number from 0 to the maximum number of channels specified in
|
|
1170
|
+
# {System.create} minus 1.
|
|
1171
|
+
#
|
|
1172
|
+
# @return [Channel] the requested channel.
|
|
1173
|
+
def channel(id)
|
|
1174
|
+
FMOD.invoke(:System_GetChannel, self, id, handle = int_ptr)
|
|
1175
|
+
Channel.new(handle)
|
|
1176
|
+
end
|
|
1177
|
+
|
|
1178
|
+
##
|
|
1179
|
+
# @return [Integer] the a speaker mode's channel count.
|
|
1180
|
+
# @param speaker_mode [Integer] the speaker mode to query.
|
|
1181
|
+
# @see SpeakerMode
|
|
1182
|
+
def speaker_mode_channels(speaker_mode)
|
|
1183
|
+
count = "\0" * SIZEOF_INT
|
|
1184
|
+
FMOD.invoke(:System_GetSpeakerModeChannels, self, speaker_mode, count)
|
|
1185
|
+
count.unpack1('l')
|
|
1186
|
+
end
|
|
1187
|
+
|
|
1188
|
+
##
|
|
1189
|
+
# @!attribute software_format
|
|
1190
|
+
# The output format for the software mixer.
|
|
1191
|
+
#
|
|
1192
|
+
# If loading Studio banks, this must be set with speaker mode
|
|
1193
|
+
# corresponding to the project's output format if there is a possibility of
|
|
1194
|
+
# the output audio device not matching the project's format. Any differences
|
|
1195
|
+
# between the project format and the system's speaker mode will cause the
|
|
1196
|
+
# mix to sound wrong.
|
|
1197
|
+
#
|
|
1198
|
+
# If not loading Studio banks, do not set this unless you explicitly want
|
|
1199
|
+
# to change a setting from the default. FMOD will default to the speaker
|
|
1200
|
+
# mode and sample rate that the OS / output prefers.
|
|
1201
|
+
#
|
|
1202
|
+
# @return [SoftwareFormat] the output format for the software mixer.
|
|
1203
|
+
|
|
1204
|
+
def software_format
|
|
1205
|
+
args = ["\0" * SIZEOF_INT, "\0" * SIZEOF_INT, "\0" * SIZEOF_INT]
|
|
1206
|
+
FMOD.invoke(:System_GetSoftwareFormat, self, *args)
|
|
1207
|
+
args.map! { |arg| arg.unpack1('l') }
|
|
1208
|
+
SoftwareFormat.new(*args)
|
|
1209
|
+
end
|
|
1210
|
+
|
|
1211
|
+
def software_format=(format)
|
|
1212
|
+
FMOD.type?(format, SoftwareFormat)
|
|
1213
|
+
FMOD.invoke(:System_GetSoftwareFormat, self, *format.values)
|
|
1214
|
+
end
|
|
1215
|
+
|
|
1216
|
+
def stream_buffer
|
|
1217
|
+
size, type = "\0" * SIZEOF_INT, "\0" * SIZEOF_INT
|
|
1218
|
+
FMOD.invoke(:System_GetStreamBufferSize, self, size, type)
|
|
1219
|
+
StreamBuffer.new(size.unpack1('L'), type.unpack1('l'))
|
|
1220
|
+
end
|
|
1221
|
+
|
|
1222
|
+
def stream_buffer=(buffer)
|
|
1223
|
+
FMOD.type?(buffer, StreamBuffer)
|
|
1224
|
+
raise RangeError, "size must be greater than 0" unless buffer.size > 0
|
|
1225
|
+
FMOD.invoke(:System_SetStreamBufferSize, self, *buffer.values)
|
|
1226
|
+
end
|
|
1227
|
+
|
|
1228
|
+
def dsp_buffer
|
|
1229
|
+
size, count = "\0" * SIZEOF_INT, "\0" * SIZEOF_INT
|
|
1230
|
+
FMOD.invoke(:System_GetDSPBufferSize, self, size, count)
|
|
1231
|
+
DspBuffer.new(size.unpack1('L'), count.unpack1('l'))
|
|
1232
|
+
end
|
|
1233
|
+
|
|
1234
|
+
def dsp_buffer=(buffer)
|
|
1235
|
+
FMOD.type?(buffer, DspBuffer)
|
|
1236
|
+
raise RangeError, "size must be greater than 0" unless buffer.size > 0
|
|
1237
|
+
FMOD.invoke(:System_SetDSPBufferSize, self, *buffer.values)
|
|
1238
|
+
end
|
|
1239
|
+
end
|
|
1240
|
+
end
|
|
1241
|
+
|
|
1242
|
+
|