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,30 @@
|
|
|
1
|
+
module FMOD
|
|
2
|
+
module Core
|
|
3
|
+
##
|
|
4
|
+
# These definitions describe the native format of the hardware or software
|
|
5
|
+
# buffer that will be used.
|
|
6
|
+
module SoundFormat
|
|
7
|
+
##
|
|
8
|
+
# Uninitialized / unknown.
|
|
9
|
+
NONE = 0
|
|
10
|
+
##
|
|
11
|
+
# 8-bit integer PCM data.
|
|
12
|
+
PCM_8 = 1
|
|
13
|
+
##
|
|
14
|
+
# 16-bit integer PCM data.
|
|
15
|
+
PCM_16 = 2
|
|
16
|
+
##
|
|
17
|
+
# 24-bit integer PCM data.
|
|
18
|
+
PCM_24 = 3
|
|
19
|
+
##
|
|
20
|
+
# 32-bit integer PCM data.
|
|
21
|
+
PCM_32 = 4
|
|
22
|
+
##
|
|
23
|
+
# 32-bit floating point PCM data.
|
|
24
|
+
PCM_FLOAT = 5
|
|
25
|
+
##
|
|
26
|
+
# Sound data is in its native compressed format.
|
|
27
|
+
BIT_STREAM = 6
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
module FMOD
|
|
2
|
+
module Core
|
|
3
|
+
##
|
|
4
|
+
# These definitions describe the type of song being played.
|
|
5
|
+
module SoundType
|
|
6
|
+
##
|
|
7
|
+
# 3rd party / unknown plugin format.
|
|
8
|
+
UNKNOWN = 0
|
|
9
|
+
##
|
|
10
|
+
# AIFF.
|
|
11
|
+
AIFF = 1
|
|
12
|
+
##
|
|
13
|
+
# Microsoft Advanced Systems Format (ie WMA/ASF/WMV).
|
|
14
|
+
ASF = 2
|
|
15
|
+
##
|
|
16
|
+
# Sound font / downloadable sound bank.
|
|
17
|
+
DLS= 3
|
|
18
|
+
##
|
|
19
|
+
# FLAC loss-less codec.
|
|
20
|
+
FLAC = 4
|
|
21
|
+
##
|
|
22
|
+
# FMOD Sample Bank.
|
|
23
|
+
FSB = 5
|
|
24
|
+
##
|
|
25
|
+
# Impulse Tracker.
|
|
26
|
+
IT = 6
|
|
27
|
+
##
|
|
28
|
+
# MIDI.
|
|
29
|
+
MIDI = 7
|
|
30
|
+
##
|
|
31
|
+
# Pro-tracker / Fast-tracker MOD.
|
|
32
|
+
MOD = 8
|
|
33
|
+
##
|
|
34
|
+
# MP2/MP3 MPEG.
|
|
35
|
+
MPEG = 9
|
|
36
|
+
##
|
|
37
|
+
# Ogg vorbis.
|
|
38
|
+
OGG_VORBIS = 10
|
|
39
|
+
##
|
|
40
|
+
# Information only from ASX/PLS/M3U/WAX play-lists.
|
|
41
|
+
PLAY_LIST = 11
|
|
42
|
+
##
|
|
43
|
+
# Raw PCM data.
|
|
44
|
+
RAW = 12
|
|
45
|
+
##
|
|
46
|
+
# ScreamTracker 3.
|
|
47
|
+
S3M = 13
|
|
48
|
+
##
|
|
49
|
+
# User created sound.
|
|
50
|
+
USER = 14
|
|
51
|
+
##
|
|
52
|
+
# Microsoft WAV.
|
|
53
|
+
WAV = 15
|
|
54
|
+
##
|
|
55
|
+
# FastTracker 2 XM.
|
|
56
|
+
XM = 16
|
|
57
|
+
##
|
|
58
|
+
# Xbox360 XMA.
|
|
59
|
+
XMA = 17
|
|
60
|
+
##
|
|
61
|
+
# iPhone hardware decoder, supports AAC, ALAC and MP3.
|
|
62
|
+
AUDIO_QUEUE = 18
|
|
63
|
+
##
|
|
64
|
+
# PS4 / PSVita ATRAC 9 format.
|
|
65
|
+
AT9 = 19
|
|
66
|
+
##
|
|
67
|
+
# Vorbis.
|
|
68
|
+
VORBIS = 20
|
|
69
|
+
##
|
|
70
|
+
# Windows Store Application built in system codecs.
|
|
71
|
+
MEDIA_FOUNDATION = 21
|
|
72
|
+
##
|
|
73
|
+
# Android MediaCodec.
|
|
74
|
+
MEDIA_CODEC = 22
|
|
75
|
+
##
|
|
76
|
+
# FMOD Adaptive Differential Pulse Code Modulation.
|
|
77
|
+
FAD_PCM = 23
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
module FMOD
|
|
2
|
+
module Core
|
|
3
|
+
module SpeakerIndex
|
|
4
|
+
FRONT_LEFT = 0
|
|
5
|
+
FRONT_RIGHT = 1
|
|
6
|
+
FRONT_CENTER = 2
|
|
7
|
+
LOW_FREQUENCY = 3
|
|
8
|
+
SURROUND_LEFT = 4
|
|
9
|
+
SURROUND_RIGHT = 5
|
|
10
|
+
BACK_LEFT = 6
|
|
11
|
+
BACK_RIGHT = 7
|
|
12
|
+
TOP_FRONT_LEFT = 8
|
|
13
|
+
TOP_FRONT_RIGHT = 9
|
|
14
|
+
TOP_BACK_LEFT = 10
|
|
15
|
+
TOP_BACK_RIGHT = 11
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require 'fiddle'
|
|
2
|
+
|
|
3
|
+
module FMOD
|
|
4
|
+
module Core
|
|
5
|
+
class Structure < Fiddle::CStructEntity
|
|
6
|
+
|
|
7
|
+
include Fiddle
|
|
8
|
+
include FMOD::Core
|
|
9
|
+
|
|
10
|
+
def initialize(address, types, members)
|
|
11
|
+
address = Pointer[address] if address.is_a?(String)
|
|
12
|
+
address ||= Fiddle.malloc(self.class.size(types)).to_i
|
|
13
|
+
super(address, types)
|
|
14
|
+
assign_names members
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def inspect
|
|
18
|
+
values = @members.map { |sym| "#{sym}=#{self[sym]}"}.join(', ')
|
|
19
|
+
super.sub(/free=0x(.)*/, values << '>')
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
|
|
2
|
+
module FMOD
|
|
3
|
+
|
|
4
|
+
module Core
|
|
5
|
+
|
|
6
|
+
WetDryMix = Struct.new(:pre_wet, :post_wet, :dry)
|
|
7
|
+
|
|
8
|
+
LoopPoints = Struct.new(:start, :start_unit, :end, :end_unit)
|
|
9
|
+
|
|
10
|
+
FadePoint = Struct.new(:clock, :volume)
|
|
11
|
+
|
|
12
|
+
##
|
|
13
|
+
# Defines the sound projection cone including the volume when outside the
|
|
14
|
+
# cone.
|
|
15
|
+
#
|
|
16
|
+
# @attr inside_angle [Float] Inside cone angle, in degrees. This is the
|
|
17
|
+
# angle within which the sound is at its normal volume.
|
|
18
|
+
#
|
|
19
|
+
# Must not be greater than {#outside_angle}.
|
|
20
|
+
# * *Default:* 360.0
|
|
21
|
+
# @attr outside_angle [Float] Outside cone angle, in degrees. This is the
|
|
22
|
+
# angle outside of which the sound is at its outside volume.
|
|
23
|
+
#
|
|
24
|
+
# Must not be less than {#inside_angle}.
|
|
25
|
+
# * *Default:* 360.0
|
|
26
|
+
# @attr outside_volume [Float] Cone outside volume.
|
|
27
|
+
# * *Minimum:* 0.0
|
|
28
|
+
# * *Maximum:* 1.0
|
|
29
|
+
# * *Default:* 1.0
|
|
30
|
+
ConeSettings = Struct.new(:inside_angle, :outside_angle, :outside_volume)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
module FMOD
|
|
2
|
+
module Core
|
|
3
|
+
class Tag < Structure
|
|
4
|
+
|
|
5
|
+
include Fiddle
|
|
6
|
+
|
|
7
|
+
def initialize(address = nil)
|
|
8
|
+
types = [TYPE_INT, TYPE_INT, TYPE_VOIDP, TYPE_VOIDP, TYPE_INT, TYPE_INT]
|
|
9
|
+
members = [:type, :data_type, :name, :data, :data_length, :updated]
|
|
10
|
+
super(address, types, members)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
[:type, :data_type, :data_length].each do |symbol|
|
|
14
|
+
define_method(symbol) { self[symbol] }
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def name
|
|
18
|
+
self[:name].to_s
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def updated
|
|
22
|
+
self[:updated] != 0
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def value
|
|
26
|
+
raw = self[:data].to_s(self[:data_length])
|
|
27
|
+
raw.delete!("\0") unless self[:data_type] == TagDataType::BINARY
|
|
28
|
+
# noinspection RubyResolve
|
|
29
|
+
case self[:data_type]
|
|
30
|
+
when TagDataType::BINARY then raw
|
|
31
|
+
when TagDataType::INT then raw.unpack1('l')
|
|
32
|
+
when TagDataType::FLOAT then raw.unpack1('f')
|
|
33
|
+
when TagDataType::STRING then raw.force_encoding('ASCII')
|
|
34
|
+
when TagDataType::STRING_UTF8 then raw.force_encoding(Encoding::UTF_8)
|
|
35
|
+
when TagDataType::STRING_UTF16 then raw.force_encoding(Encoding::UTF_16)
|
|
36
|
+
when TagDataType::STRING_UTF16BE then raw.force_encoding(Encoding::UTF_16BE)
|
|
37
|
+
else ''
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def to_s
|
|
42
|
+
begin
|
|
43
|
+
"#{value}"
|
|
44
|
+
rescue Encoding::CompatibilityError
|
|
45
|
+
value.inspect
|
|
46
|
+
# TODO
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
module FMOD
|
|
2
|
+
module Core
|
|
3
|
+
module TimeUnit
|
|
4
|
+
|
|
5
|
+
##
|
|
6
|
+
# Milliseconds.
|
|
7
|
+
MS = 0x00000001
|
|
8
|
+
|
|
9
|
+
##
|
|
10
|
+
# PCM samples, related to milliseconds * sample rate / 1000.
|
|
11
|
+
PCM = 0x00000002
|
|
12
|
+
|
|
13
|
+
##
|
|
14
|
+
# Bytes, related to PCM samples * channels * data width (ie 16bit = 2 bytes).
|
|
15
|
+
PCM_BYTES = 0x00000004
|
|
16
|
+
|
|
17
|
+
##
|
|
18
|
+
# Raw file bytes of (compressed) sound data (does not include headers).
|
|
19
|
+
RAW_BYTES = 0x00000008
|
|
20
|
+
|
|
21
|
+
##
|
|
22
|
+
# Fractions of 1 PCM sample. Unsigned integer range 0 to 0xFFFFFFFF.
|
|
23
|
+
#
|
|
24
|
+
# Used for sub-sample granularity for DSP purposes.
|
|
25
|
+
PCM_FRACTION = 0x00000010
|
|
26
|
+
|
|
27
|
+
##
|
|
28
|
+
# MOD/S3M/XM/IT. Order in a sequenced module format.
|
|
29
|
+
MOD_ORDER = 0x00000100
|
|
30
|
+
|
|
31
|
+
##
|
|
32
|
+
# MOD/S3M/XM/IT. Current row in a sequenced module format.
|
|
33
|
+
MOD_ROW = 0x00000200
|
|
34
|
+
|
|
35
|
+
##
|
|
36
|
+
# MOD/S3M/XM/IT. Current pattern in a sequenced module format.
|
|
37
|
+
MOD_PATTERN = 0x00000400
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
module FMOD
|
|
2
|
+
module Core
|
|
3
|
+
# @attr x [Float]
|
|
4
|
+
# @attr y [Float]
|
|
5
|
+
# @attr z [Float]
|
|
6
|
+
class Vector < Structure
|
|
7
|
+
|
|
8
|
+
def self.zero
|
|
9
|
+
new(0.0, 0.0, 0.0)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def self.one
|
|
13
|
+
new(1.0, 1.0, 1.0)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def initialize(*args)
|
|
17
|
+
address ||= args.size == 1 ? args.first : nil
|
|
18
|
+
members = [:x, :y, :z]
|
|
19
|
+
types = Array.new(3, TYPE_FLOAT)
|
|
20
|
+
super(address, types, members)
|
|
21
|
+
set(*args) if args.size == 3
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
[:x, :y, :z].each do |symbol|
|
|
25
|
+
define_method(symbol) { self[symbol] }
|
|
26
|
+
define_method("#{symbol}=") { |value| self[symbol] = value.to_f }
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def set(x, y, z)
|
|
30
|
+
self[:x], self[:y], self[:z] = x, y, z
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def to_a
|
|
34
|
+
@members.map { |sym| self[sym] }
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def to_h
|
|
38
|
+
{ x: self[:x], y: self[:y], z: self[:z] }
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
data/lib/fmod/dsp.rb
ADDED
|
@@ -0,0 +1,510 @@
|
|
|
1
|
+
module FMOD
|
|
2
|
+
|
|
3
|
+
# @attr wet_dry_mix [WetDryMix] Allows the user to scale the affect of a DSP
|
|
4
|
+
# effect, through control of the "wet" mix, which is the post-processed
|
|
5
|
+
# signal and the "dry" which is the pre-processed signal.
|
|
6
|
+
#
|
|
7
|
+
# The dry signal path is silent by default, because DSP effects transform
|
|
8
|
+
# the input and pass the newly processed result to the output. It does not
|
|
9
|
+
# add to the input.
|
|
10
|
+
class Dsp < Handle
|
|
11
|
+
|
|
12
|
+
ChannelFormat = Struct.new(:mask, :count, :speaker_mode)
|
|
13
|
+
|
|
14
|
+
DspInfo = Struct.new(:name, :version, :channels, :width, :height) do
|
|
15
|
+
def config?
|
|
16
|
+
width > 0 && height > 0
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
##
|
|
21
|
+
# Retrieves a hash mapping the class of each DSP to its corresponding
|
|
22
|
+
# integer type defined in {DspType}.
|
|
23
|
+
# @return [Hash{Integer=>Class}]
|
|
24
|
+
def self.type_map(type)
|
|
25
|
+
@type_map ||= {
|
|
26
|
+
DspType::MIXER => FMOD::Effects::Mixer,
|
|
27
|
+
DspType::OSCILLATOR => FMOD::Effects::Oscillator,
|
|
28
|
+
DspType::LOW_PASS => FMOD::Effects::LowPass,
|
|
29
|
+
DspType::IT_LOW_PASS => FMOD::Effects::ITLowPass,
|
|
30
|
+
DspType::HIGH_PASS => FMOD::Effects::HighPass,
|
|
31
|
+
DspType::ECHO => FMOD::Effects::Echo,
|
|
32
|
+
DspType::FADER => FMOD::Effects::Fader,
|
|
33
|
+
DspType::FLANGE => FMOD::Effects::Flange,
|
|
34
|
+
DspType::DISTORTION => FMOD::Effects::Distortion,
|
|
35
|
+
DspType::NORMALIZE => FMOD::Effects::Normalize,
|
|
36
|
+
DspType::LIMITER => FMOD::Effects::Limiter,
|
|
37
|
+
DspType::PARAM_EQ => FMOD::Effects::ParamEq,
|
|
38
|
+
DspType::PITCH_SHIFT => FMOD::Effects::PitchShift,
|
|
39
|
+
DspType::CHORUS => FMOD::Effects::Chorus,
|
|
40
|
+
DspType::VST_PLUGIN => FMOD::Effects::VstPlugin,
|
|
41
|
+
DspType::WINAMP_PLUGIN => FMOD::Effects::WinampPlugin,
|
|
42
|
+
DspType::IT_ECHO => FMOD::Effects::ITEcho,
|
|
43
|
+
DspType::COMPRESSOR => FMOD::Effects::Compressor,
|
|
44
|
+
DspType::SFX_REVERB => FMOD::Effects::SfxReverb,
|
|
45
|
+
DspType::LOW_PASS_SIMPLE => FMOD::Effects::LowPassSimple,
|
|
46
|
+
DspType::DELAY => FMOD::Effects::Delay,
|
|
47
|
+
DspType::TREMOLO => FMOD::Effects::Tremolo,
|
|
48
|
+
DspType::LADSPA_PLUGIN => FMOD::Effects::LadspaPlugin,
|
|
49
|
+
DspType::SEND => FMOD::Effects::Send,
|
|
50
|
+
DspType::RETURN => FMOD::Effects::Return,
|
|
51
|
+
DspType::HIGH_PASS_SIMPLE => FMOD::Effects::HighPassSimple,
|
|
52
|
+
DspType::PAN => FMOD::Effects::Pan,
|
|
53
|
+
DspType::THREE_EQ => FMOD::Effects::ThreeEq,
|
|
54
|
+
DspType::FFT => FMOD::Effects::FFT,
|
|
55
|
+
DspType::LOUDNESS_METER => FMOD::Effects::LoudnessMeter,
|
|
56
|
+
DspType::ENVELOPE_FOLLOWER => FMOD::Effects::EnvelopeFollower,
|
|
57
|
+
DspType::CONVOLUTION_REVERB => FMOD::Effects::ConvolutionReverb,
|
|
58
|
+
DspType::CHANNEL_MIX => FMOD::Effects::ChannelMix,
|
|
59
|
+
DspType::TRANSCEIVER => FMOD::Effects::Transceiver,
|
|
60
|
+
DspType::OBJECT_PAN => FMOD::Effects::ObjectPan,
|
|
61
|
+
DspType::MULTIBAND_EQ => FMOD::Effects::MultibandEq
|
|
62
|
+
}
|
|
63
|
+
return @type_map[type] if type.is_a?(Integer)
|
|
64
|
+
return @type_map.key(type) if type.is_a?(Class)
|
|
65
|
+
raise TypeError, "#{type} is not a Integer or Class."
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def play(group = nil)
|
|
69
|
+
parent.play_dsp(self, group, false)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
##
|
|
73
|
+
# Converts the specified memory address to a DSP of the appropriate
|
|
74
|
+
# sub-type instead of generic {Dsp} type.
|
|
75
|
+
# @param address [Integer|String|Pointer] The memory address of the DSP.
|
|
76
|
+
# @return [Dsp] A DSP class found in {FMOD::Effects}.
|
|
77
|
+
def self.from_handle(address)
|
|
78
|
+
address = address.unpack1('J') if address.is_a?(String)
|
|
79
|
+
type = "\0" * SIZEOF_INT
|
|
80
|
+
FMOD.invoke(:DSP_GetType, address.to_i, type)
|
|
81
|
+
klass = type_map(type.unpack1('l')) rescue Dsp
|
|
82
|
+
klass.new(address)
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
##
|
|
86
|
+
# @!attribute [r] type
|
|
87
|
+
# Retrieves the pre-defined type of a FMOD registered DSP unit.
|
|
88
|
+
#
|
|
89
|
+
# @return [Integer]
|
|
90
|
+
# @see DspType
|
|
91
|
+
integer_reader(:type, :DSP_GetType)
|
|
92
|
+
|
|
93
|
+
##
|
|
94
|
+
# @!attribute [r] parameter_count
|
|
95
|
+
# Retrieves the number of parameters a DSP unit has to control its
|
|
96
|
+
# behavior.
|
|
97
|
+
#
|
|
98
|
+
# @return [Integer]
|
|
99
|
+
integer_reader(:parameter_count, :DSP_GetNumParameters)
|
|
100
|
+
|
|
101
|
+
##
|
|
102
|
+
# @!attribute [r] input_count
|
|
103
|
+
# Retrieves the number of inputs connected to the DSP unit.
|
|
104
|
+
#
|
|
105
|
+
# Inputs are units that feed data to this unit. When there are multiple
|
|
106
|
+
# inputs, they are mixed together.
|
|
107
|
+
#
|
|
108
|
+
# @note Because this function needs to flush the DSP queue before it can
|
|
109
|
+
# determine how many units are available, this function may block
|
|
110
|
+
# significantly while the background mixer thread operates.
|
|
111
|
+
# @return [Integer]
|
|
112
|
+
integer_reader(:input_count, :DSP_GetNumInputs)
|
|
113
|
+
|
|
114
|
+
##
|
|
115
|
+
# @!attribute [r] output_count
|
|
116
|
+
# Retrieves the number of outputs connected to the DSP unit.
|
|
117
|
+
#
|
|
118
|
+
# Outputs are units that this unit feeds data to. When there are multiple
|
|
119
|
+
# outputs, the data is split and sent to each unit individually.
|
|
120
|
+
#
|
|
121
|
+
# @note Because this function needs to flush the DSP queue before it can
|
|
122
|
+
# determine how many units are available, this function may block
|
|
123
|
+
# significantly while the background mixer thread operates.
|
|
124
|
+
#
|
|
125
|
+
# @return [Integer]
|
|
126
|
+
integer_reader(:output_count, :DSP_GetNumOutputs)
|
|
127
|
+
|
|
128
|
+
##
|
|
129
|
+
# @!method idle?
|
|
130
|
+
# Retrieves the idle state of a DSP. A DSP is idle when no signal is
|
|
131
|
+
# coming into it. This can be a useful method of determining if a DSP sub
|
|
132
|
+
# branch is finished processing, so it can be disconnected for example.
|
|
133
|
+
#
|
|
134
|
+
# @return [Boolean]
|
|
135
|
+
bool_reader(:idle?, :DSP_GetIdle)
|
|
136
|
+
|
|
137
|
+
##
|
|
138
|
+
# @!attribute active
|
|
139
|
+
# Gets or sets the enabled state of a unit for being processed.
|
|
140
|
+
#
|
|
141
|
+
# This does not connect or disconnect a unit in any way, it just disables
|
|
142
|
+
# it so that it is not processed.
|
|
143
|
+
#
|
|
144
|
+
# If a unit is disabled, and has inputs, they will also cease to be
|
|
145
|
+
# processed.
|
|
146
|
+
#
|
|
147
|
+
# To disable a unit but allow the inputs of the unit to continue being
|
|
148
|
+
# processed, use {#bypass} instead.
|
|
149
|
+
#
|
|
150
|
+
# @return [Boolean]
|
|
151
|
+
bool_reader(:active, :DSP_GetActive)
|
|
152
|
+
bool_writer(:active=, :DSP_SetActive)
|
|
153
|
+
|
|
154
|
+
##
|
|
155
|
+
# @!attribute bypass
|
|
156
|
+
# Enables or disables the read callback of a DSP unit so that it does or
|
|
157
|
+
# doesn't process the data coming into it.
|
|
158
|
+
#
|
|
159
|
+
# A DSP unit that is disabled still processes its inputs, it will just be
|
|
160
|
+
# "dry".
|
|
161
|
+
#
|
|
162
|
+
# If a unit is bypassed, it will still process its inputs.
|
|
163
|
+
#
|
|
164
|
+
# To disable the unit and all of its inputs, use {#active} instead.
|
|
165
|
+
# @return [Boolean]
|
|
166
|
+
bool_reader(:bypass, :DSP_GetBypass)
|
|
167
|
+
bool_writer(:bypass=, :DSP_SetBypass)
|
|
168
|
+
|
|
169
|
+
##
|
|
170
|
+
# Retrieves the name of this DSP unit.
|
|
171
|
+
# @return [String]
|
|
172
|
+
def name
|
|
173
|
+
name = "\0" * 32
|
|
174
|
+
FMOD.invoke(:DSP_GetInfo, self, name, nil, nil, nil, nil)
|
|
175
|
+
name.delete("\0")
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
##
|
|
179
|
+
# Retrieves the version of this DSP as string.
|
|
180
|
+
# @return [String]
|
|
181
|
+
def version
|
|
182
|
+
vs = "\0" * SIZEOF_INT
|
|
183
|
+
FMOD.invoke(:DSP_GetInfo, self, nil, vs, nil, nil, nil)
|
|
184
|
+
version = vs.unpack1('L').to_s(16).rjust(8, '0')
|
|
185
|
+
"#{version[0, 4].to_i}.#{version[4, 4].to_i}"
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def wet_dry_mix
|
|
189
|
+
args = ["\0" * SIZEOF_FLOAT, "\0" * SIZEOF_FLOAT, "\0" * SIZEOF_FLOAT]
|
|
190
|
+
FMOD.invoke(:DSP_GetWetDryMix, self, *args)
|
|
191
|
+
args.map! { |arg| arg.unpack1('f') }
|
|
192
|
+
WetDryMix.new(*args)
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
def wet_dry_mix=(mix)
|
|
196
|
+
FMOD.type?(mix, WetDryMix)
|
|
197
|
+
FMOD.invoke(:DSP_SetWetDryMix, self, *mix.values)
|
|
198
|
+
mix
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
##
|
|
202
|
+
# Allows the user to scale the affect of a DSP effect, through control of
|
|
203
|
+
# the "wet" mix, which is the post-processed signal and the "dry" which is
|
|
204
|
+
# the pre-processed signal.
|
|
205
|
+
#
|
|
206
|
+
# The dry signal path is silent by default, because dsp effects transform
|
|
207
|
+
# the input and pass the newly processed result to the output. It does not
|
|
208
|
+
# add to the input.
|
|
209
|
+
#
|
|
210
|
+
# @param pre_wet [Float] Floating point value from 0 to 1, describing a
|
|
211
|
+
# linear scale of the "wet" (pre-processed signal) mix of the effect.
|
|
212
|
+
# Scale can be lower than 0 (negating) and higher than 1 (amplifying). *
|
|
213
|
+
# * *Default:* 1.0
|
|
214
|
+
# @param post_wet [Float] Floating point value from 0 to 1, describing a
|
|
215
|
+
# linear scale of the "wet" (post-processed signal) mix of the effect.
|
|
216
|
+
# Scale can be lower than 0 (negating) and higher than 1 (amplifying).
|
|
217
|
+
# * *Default:* 1.0
|
|
218
|
+
# @param dry [Float] Floating point value from 0 to 1, describing a linear
|
|
219
|
+
# scale of the "dry" (pre-processed signal) mix of the effect. Scale can
|
|
220
|
+
# be lower than 0 and higher than 1 (amplifying).
|
|
221
|
+
# * *Default:* 0.0
|
|
222
|
+
#
|
|
223
|
+
# @return [self]
|
|
224
|
+
def set_wet_dry_mix(pre_wet, post_wet, dry)
|
|
225
|
+
FMOD.invoke(:DSP_SetWetDryMix, self, pre_wet, post_wet, dry)
|
|
226
|
+
self
|
|
227
|
+
end
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def channel_format
|
|
238
|
+
args = ["\0" * SIZEOF_INT, "\0" * SIZEOF_INT, "\0" * SIZEOF_INT]
|
|
239
|
+
FMOD.invoke(:DSP_GetChannelFormat, self, *args)
|
|
240
|
+
args.map! { |arg| arg.unpack1('L') }
|
|
241
|
+
ChannelFormat.new(*args)
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
def channel_format=(format)
|
|
245
|
+
FMOD.type?(format, ChannelFormat)
|
|
246
|
+
FMOD.invoke(:DSP_GetChannelFormat, self, *format.values)
|
|
247
|
+
format
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
def param_info(index)
|
|
251
|
+
return nil unless FMOD.valid_range?(index, 0, parameter_count, false)
|
|
252
|
+
FMOD.invoke(:DSP_GetParameterInfo, self, index, info = int_ptr)
|
|
253
|
+
ParameterInfo.new(info.unpack1('J'))
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
def to_s
|
|
257
|
+
"#{name} v.#{version}"
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
def info
|
|
261
|
+
name, vs = "\0" * 32, "\0" * SIZEOF_INT
|
|
262
|
+
args = ["\0" * SIZEOF_INT, "\0" * SIZEOF_INT, "\0" * SIZEOF_INT]
|
|
263
|
+
FMOD.invoke(:DSP_GetInfo, self, name, vs, *args)
|
|
264
|
+
args = args.map { |arg| arg.unpack1('l') }
|
|
265
|
+
vs = vs.unpack1('L').to_s(16).rjust(8, '0')
|
|
266
|
+
version = "#{vs[0, 4].to_i}.#{vs[4, 4].to_i}"
|
|
267
|
+
DspInfo.new(name.delete("\0"), version, *args)
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
def reset
|
|
271
|
+
FMOD.invoke(:DSP_Reset, self)
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
def parent
|
|
275
|
+
FMOD.invoke(:DSP_GetSystemObject, self, system = int_ptr)
|
|
276
|
+
System.new(system)
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
def show_dialog(hwnd, show = true)
|
|
280
|
+
FMOD.invoke(:DSP_ShowConfigDialog, self, hwnd, show.to_i)
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
def disconnect(inputs, outputs)
|
|
284
|
+
FMOD.invoke(:DSP_DisconnectAll, self, inputs.to_i, outputs.to_i)
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
def disconnect_from(dsp, connection = nil)
|
|
288
|
+
FMOD.type?(dsp, Dsp) unless dsp.nil?
|
|
289
|
+
FMOD.type?(connection, DspConnection) unless connection.nil?
|
|
290
|
+
FMOD.invoke(:DSP_DisconnectFrom, self, dsp, connection)
|
|
291
|
+
end
|
|
292
|
+
|
|
293
|
+
def output_format(*args)
|
|
294
|
+
if args.size == 3 && args.all? { |arg| arg.is_a?(Integer) }
|
|
295
|
+
mask, count, mode = args
|
|
296
|
+
elsif args.size == 1 && FMOD.type?(args[0], ChannelFormat)
|
|
297
|
+
mask, count, mode = args[0].values
|
|
298
|
+
else
|
|
299
|
+
mask, count, mode = channel_format.values
|
|
300
|
+
end
|
|
301
|
+
args = ["\0" * SIZEOF_INT, "\0" * SIZEOF_INT, "\0" * SIZEOF_INT]
|
|
302
|
+
FMOD.invoke(:DSP_GetOutputChannelFormat, mask, count, mode, *args)
|
|
303
|
+
args.map! { |arg| arg.unpack1('L') }
|
|
304
|
+
ChannelFormat.new(*args)
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
def input(index)
|
|
308
|
+
input = int_ptr
|
|
309
|
+
FMOD.invoke(:DSP_GetInput, self, index, input, nil)
|
|
310
|
+
Dsp.from_handle(input)
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
def output(index)
|
|
314
|
+
output = int_ptr
|
|
315
|
+
FMOD.invoke(:DSP_GetOutput, self, index, output, nil)
|
|
316
|
+
Dsp.from_handle(output)
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
def input_connection(index)
|
|
320
|
+
connection = int_ptr
|
|
321
|
+
FMOD.invoke(:DSP_GetInput, self, index, nil, connection)
|
|
322
|
+
DspConnection.new(connection)
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
def output_connection(index)
|
|
326
|
+
connection = int_ptr
|
|
327
|
+
FMOD.invoke(:DSP_GetOutput, self, index, nil, connection)
|
|
328
|
+
DspConnection.new(connection)
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
def add_input(dsp, type)
|
|
332
|
+
FMOD.type?(dsp, Dsp)
|
|
333
|
+
connection = int_ptr
|
|
334
|
+
FMOD.invoke(:DSP_AddInput, self, dsp, connection, type)
|
|
335
|
+
DspConnection.new(connection)
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
def input_metering?
|
|
339
|
+
enabled = "\0" * SIZEOF_INT
|
|
340
|
+
FMOD.invoke(:DSP_GetMeteringEnabled, self, enabled, nil)
|
|
341
|
+
enabled.unpack1('l') != 0
|
|
342
|
+
end
|
|
343
|
+
|
|
344
|
+
def output_metering?
|
|
345
|
+
enabled = "\0" * SIZEOF_INT
|
|
346
|
+
FMOD.invoke(:DSP_GetMeteringEnabled, self, nil, enabled)
|
|
347
|
+
enabled.unpack1('l') != 0
|
|
348
|
+
end
|
|
349
|
+
|
|
350
|
+
def enable_metering(input, output)
|
|
351
|
+
FMOD.invoke(:DSP_SetMeteringEnabled, self, input ? 1 :0, output.to_i)
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
def [](index)
|
|
355
|
+
return nil unless FMOD.valid_range?(index, 0, parameter_count, false)
|
|
356
|
+
case param_info(index).type
|
|
357
|
+
when ParameterType::FLOAT then get_float(index)
|
|
358
|
+
when ParameterType::INT then get_integer(index)
|
|
359
|
+
when ParameterType::BOOL then get_integer(index)
|
|
360
|
+
when ParameterType::DATA then get_data(index)
|
|
361
|
+
else raise RangeError, 'Unknown data type.'
|
|
362
|
+
end
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
def get_float(index)
|
|
366
|
+
return nil unless FMOD.valid_range?(index, 0, parameter_count, false)
|
|
367
|
+
buffer = "\0" * SIZEOF_FLOAT
|
|
368
|
+
FMOD.invoke(:DSP_GetParameterFloat, self, index, buffer, nil, 0)
|
|
369
|
+
buffer.unpack1('f')
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
def get_integer(index)
|
|
373
|
+
return nil unless FMOD.valid_range?(index, 0, parameter_count, false)
|
|
374
|
+
buffer = "\0" * SIZEOF_INT
|
|
375
|
+
FMOD.invoke(:DSP_GetParameterInt, self, index, buffer, nil, 0)
|
|
376
|
+
buffer.unpack1('l')
|
|
377
|
+
end
|
|
378
|
+
|
|
379
|
+
def get_bool(index)
|
|
380
|
+
return nil unless FMOD.valid_range?(index, 0, parameter_count, false)
|
|
381
|
+
buffer = "\0" * SIZEOF_INT
|
|
382
|
+
FMOD.invoke(:DSP_GetParameterBool, self, index, buffer, nil, 0)
|
|
383
|
+
buffer.unpack1('l') != 0
|
|
384
|
+
end
|
|
385
|
+
|
|
386
|
+
def get_data(index)
|
|
387
|
+
return nil unless FMOD.valid_range?(index, 0, parameter_count, false)
|
|
388
|
+
pointer = int_ptr
|
|
389
|
+
size = "\0" * SIZEOF_INT
|
|
390
|
+
FMOD.invoke(:DSP_GetParameterData, self, index, pointer, size, nil, 0)
|
|
391
|
+
Pointer.new(pointer.unpack('J'), size.unpack1('l'))
|
|
392
|
+
end
|
|
393
|
+
|
|
394
|
+
def []=(index, value)
|
|
395
|
+
return unless FMOD.valid_range?(index, 0, parameter_count, false)
|
|
396
|
+
case value
|
|
397
|
+
when Float then set_float(index, value)
|
|
398
|
+
when Integer then set_integer(index, value)
|
|
399
|
+
when TrueClass, FalseClass, NilClass then set_bool(index, value)
|
|
400
|
+
when String, Pointer then set_data(index, value)
|
|
401
|
+
else raise TypeError, "#{value} is not a valid DSP parameter type."
|
|
402
|
+
end
|
|
403
|
+
end
|
|
404
|
+
|
|
405
|
+
def set_float(index, value)
|
|
406
|
+
return unless FMOD.valid_range?(index, 0, parameter_count, false)
|
|
407
|
+
FMOD.invoke(:DSP_SetParameterFloat, self, index, value)
|
|
408
|
+
self
|
|
409
|
+
end
|
|
410
|
+
|
|
411
|
+
def set_integer(index, value)
|
|
412
|
+
return unless FMOD.valid_range?(index, 0, parameter_count, false)
|
|
413
|
+
FMOD.invoke(:DSP_SetParameterInt, self, index, value)
|
|
414
|
+
self
|
|
415
|
+
end
|
|
416
|
+
|
|
417
|
+
def set_bool(index, value)
|
|
418
|
+
return unless FMOD.valid_range?(index, 0, parameter_count, false)
|
|
419
|
+
FMOD.invoke(:DSP_SetParameterBool, self, index, value.to_i)
|
|
420
|
+
self
|
|
421
|
+
end
|
|
422
|
+
|
|
423
|
+
def set_data(index, value)
|
|
424
|
+
return unless FMOD.valid_range?(index, 0, parameter_count, false)
|
|
425
|
+
unless FMOD.type?(value, String, false)
|
|
426
|
+
FMOD.type?(value, Pointer)
|
|
427
|
+
end
|
|
428
|
+
size = value.is_a?(String) ? value.bytesize : value.size
|
|
429
|
+
FMOD.invoke(:DSP_SetParameterData, self, index, value, size)
|
|
430
|
+
self
|
|
431
|
+
end
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
class << self
|
|
435
|
+
|
|
436
|
+
private
|
|
437
|
+
|
|
438
|
+
def float_param(index, name, **options)
|
|
439
|
+
define_method(name) { get_float(index) } unless options[:write_only]
|
|
440
|
+
unless options[:readonly]
|
|
441
|
+
define_method("#{name}=") do |value|
|
|
442
|
+
value = options[:min] if options[:min] && value < options[:min]
|
|
443
|
+
value = options[:max] if options[:max] && value > options[:max]
|
|
444
|
+
set_float(index, value)
|
|
445
|
+
end
|
|
446
|
+
end
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
def integer_param(index, name, **options)
|
|
450
|
+
define_method(name) { get_integer(index) } unless options[:write_only]
|
|
451
|
+
unless options[:readonly]
|
|
452
|
+
define_method("#{name}=") do |value|
|
|
453
|
+
value = options[:min] if options[:min] && value < options[:min]
|
|
454
|
+
value = options[:max] if options[:max] && value > options[:max]
|
|
455
|
+
set_float(index, value)
|
|
456
|
+
end
|
|
457
|
+
end
|
|
458
|
+
end
|
|
459
|
+
|
|
460
|
+
def bool_param(index, name, **options)
|
|
461
|
+
define_method(name) { get_bool(index) } unless options[:write_only]
|
|
462
|
+
unless options[:readonly]
|
|
463
|
+
define_method("#{name}=") { |value| set_bool(index, value) }
|
|
464
|
+
end
|
|
465
|
+
end
|
|
466
|
+
|
|
467
|
+
def data_param(index, name, **options)
|
|
468
|
+
define_method(name) { get_data(index) } unless options[:write_only]
|
|
469
|
+
unless options[:readonly]
|
|
470
|
+
define_method("#{name}=") { |value| set_data(index, value) }
|
|
471
|
+
end
|
|
472
|
+
end
|
|
473
|
+
end
|
|
474
|
+
# def self.float_param(index, name, **options)
|
|
475
|
+
# define_method(name) { get_float(index) } unless options[:write_only]
|
|
476
|
+
# unless options[:readonly]
|
|
477
|
+
# define_method("#{name}=") do |value|
|
|
478
|
+
# value = options[:min] if options[:min] && value < options[:min]
|
|
479
|
+
# value = options[:max] if options[:max] && value > options[:max]
|
|
480
|
+
# set_float(index, value)
|
|
481
|
+
# end
|
|
482
|
+
# end
|
|
483
|
+
# end
|
|
484
|
+
#
|
|
485
|
+
# def self.integer_param(index, name, **options)
|
|
486
|
+
# define_method(name) { get_integer(index) } unless options[:write_only]
|
|
487
|
+
# unless options[:readonly]
|
|
488
|
+
# define_method("#{name}=") do |value|
|
|
489
|
+
# value = options[:min] if options[:min] && value < options[:min]
|
|
490
|
+
# value = options[:max] if options[:max] && value > options[:max]
|
|
491
|
+
# set_float(index, value)
|
|
492
|
+
# end
|
|
493
|
+
# end
|
|
494
|
+
# end
|
|
495
|
+
#
|
|
496
|
+
# def self.bool_param(index, name, **options)
|
|
497
|
+
# define_method(name) { get_bool(index) } unless options[:write_only]
|
|
498
|
+
# unless options[:readonly]
|
|
499
|
+
# define_method("#{name}=") { |value| set_bool(index, value) }
|
|
500
|
+
# end
|
|
501
|
+
# end
|
|
502
|
+
#
|
|
503
|
+
# def self.data_param(index, name, **options)
|
|
504
|
+
# define_method(name) { get_data(index) } unless options[:write_only]
|
|
505
|
+
# unless options[:readonly]
|
|
506
|
+
# define_method("#{name}=") { |value| set_data(index, value) }
|
|
507
|
+
# end
|
|
508
|
+
# end
|
|
509
|
+
end
|
|
510
|
+
end
|