fmod 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (105) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +14 -0
  3. data/.travis.yml +5 -0
  4. data/.yardopts +2 -0
  5. data/CODE_OF_CONDUCT.md +74 -0
  6. data/Gemfile +5 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +96 -0
  9. data/Rakefile +1 -0
  10. data/bin/console +28 -0
  11. data/bin/setup +8 -0
  12. data/ext/fmod.dll +0 -0
  13. data/ext/fmod64.dll +0 -0
  14. data/ext/libfmod.dylib +0 -0
  15. data/ext/llbfmod.zip +0 -0
  16. data/extras/FMOD Studio Programmers API for Windows.chm +0 -0
  17. data/fmod.gemspec +58 -0
  18. data/lib/fmod.rb +564 -0
  19. data/lib/fmod/channel.rb +151 -0
  20. data/lib/fmod/channel_control.rb +821 -0
  21. data/lib/fmod/channel_group.rb +61 -0
  22. data/lib/fmod/core.rb +35 -0
  23. data/lib/fmod/core/bool_description.rb +18 -0
  24. data/lib/fmod/core/channel_mask.rb +24 -0
  25. data/lib/fmod/core/data_description.rb +14 -0
  26. data/lib/fmod/core/driver.rb +59 -0
  27. data/lib/fmod/core/dsp_description.rb +7 -0
  28. data/lib/fmod/core/dsp_index.rb +9 -0
  29. data/lib/fmod/core/dsp_type.rb +43 -0
  30. data/lib/fmod/core/extensions.rb +28 -0
  31. data/lib/fmod/core/file_system.rb +86 -0
  32. data/lib/fmod/core/filter_type.rb +19 -0
  33. data/lib/fmod/core/float_description.rb +16 -0
  34. data/lib/fmod/core/guid.rb +50 -0
  35. data/lib/fmod/core/init_flags.rb +19 -0
  36. data/lib/fmod/core/integer_description.rb +26 -0
  37. data/lib/fmod/core/mode.rb +36 -0
  38. data/lib/fmod/core/output_type.rb +30 -0
  39. data/lib/fmod/core/parameter_info.rb +41 -0
  40. data/lib/fmod/core/parameter_type.rb +10 -0
  41. data/lib/fmod/core/result.rb +88 -0
  42. data/lib/fmod/core/reverb.rb +217 -0
  43. data/lib/fmod/core/sound_ex_info.rb +7 -0
  44. data/lib/fmod/core/sound_format.rb +30 -0
  45. data/lib/fmod/core/sound_group_behavior.rb +9 -0
  46. data/lib/fmod/core/sound_type.rb +80 -0
  47. data/lib/fmod/core/speaker_index.rb +18 -0
  48. data/lib/fmod/core/speaker_mode.rb +16 -0
  49. data/lib/fmod/core/spectrum_data.rb +12 -0
  50. data/lib/fmod/core/structure.rb +23 -0
  51. data/lib/fmod/core/structures.rb +41 -0
  52. data/lib/fmod/core/tag.rb +51 -0
  53. data/lib/fmod/core/tag_data_type.rb +14 -0
  54. data/lib/fmod/core/time_unit.rb +40 -0
  55. data/lib/fmod/core/vector.rb +42 -0
  56. data/lib/fmod/core/window_type.rb +12 -0
  57. data/lib/fmod/dsp.rb +510 -0
  58. data/lib/fmod/dsp_connection.rb +113 -0
  59. data/lib/fmod/effects.rb +38 -0
  60. data/lib/fmod/effects/channel_mix.rb +101 -0
  61. data/lib/fmod/effects/chorus.rb +30 -0
  62. data/lib/fmod/effects/compressor.rb +52 -0
  63. data/lib/fmod/effects/convolution_reverb.rb +31 -0
  64. data/lib/fmod/effects/delay.rb +44 -0
  65. data/lib/fmod/effects/distortion.rb +16 -0
  66. data/lib/fmod/effects/dsps.rb +10 -0
  67. data/lib/fmod/effects/echo.rb +37 -0
  68. data/lib/fmod/effects/envelope_follower.rb +31 -0
  69. data/lib/fmod/effects/fader.rb +16 -0
  70. data/lib/fmod/effects/fft.rb +38 -0
  71. data/lib/fmod/effects/flange.rb +37 -0
  72. data/lib/fmod/effects/high_pass.rb +24 -0
  73. data/lib/fmod/effects/high_pass_simple.rb +25 -0
  74. data/lib/fmod/effects/it_echo.rb +56 -0
  75. data/lib/fmod/effects/it_lowpass.rb +36 -0
  76. data/lib/fmod/effects/ladspa_plugin.rb +14 -0
  77. data/lib/fmod/effects/limiter.rb +32 -0
  78. data/lib/fmod/effects/loudness_meter.rb +19 -0
  79. data/lib/fmod/effects/low_pass.rb +25 -0
  80. data/lib/fmod/effects/low_pass_simple.rb +26 -0
  81. data/lib/fmod/effects/mixer.rb +11 -0
  82. data/lib/fmod/effects/multiband_eq.rb +153 -0
  83. data/lib/fmod/effects/normalize.rb +47 -0
  84. data/lib/fmod/effects/object_pan.rb +62 -0
  85. data/lib/fmod/effects/oscillator.rb +52 -0
  86. data/lib/fmod/effects/pan.rb +166 -0
  87. data/lib/fmod/effects/param_eq.rb +36 -0
  88. data/lib/fmod/effects/pitch_shift.rb +47 -0
  89. data/lib/fmod/effects/return.rb +18 -0
  90. data/lib/fmod/effects/send.rb +21 -0
  91. data/lib/fmod/effects/sfx_reverb.rb +87 -0
  92. data/lib/fmod/effects/three_eq.rb +41 -0
  93. data/lib/fmod/effects/transceiver.rb +57 -0
  94. data/lib/fmod/effects/tremolo.rb +67 -0
  95. data/lib/fmod/effects/vst_plugin.rb +12 -0
  96. data/lib/fmod/effects/winamp_plugin.rb +12 -0
  97. data/lib/fmod/error.rb +108 -0
  98. data/lib/fmod/geometry.rb +380 -0
  99. data/lib/fmod/handle.rb +129 -0
  100. data/lib/fmod/reverb3D.rb +98 -0
  101. data/lib/fmod/sound.rb +810 -0
  102. data/lib/fmod/sound_group.rb +54 -0
  103. data/lib/fmod/system.rb +1242 -0
  104. data/lib/fmod/version.rb +3 -0
  105. metadata +220 -0
@@ -0,0 +1,7 @@
1
+ module FMOD
2
+ module Core
3
+ class SoundExInfo < Structure
4
+ # TODO
5
+ end
6
+ end
7
+ end
@@ -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,9 @@
1
+ module FMOD
2
+ module Core
3
+ module SoundGroupBehavior
4
+ FAIL = 0
5
+ MUTE = 1
6
+ STEAL_LOWEST = 2
7
+ end
8
+ end
9
+ 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,16 @@
1
+
2
+ module FMOD
3
+ module Core
4
+ module SpeakerMode
5
+ DEFAULT = 0
6
+ RAW = 1
7
+ MONO = 2
8
+ STEREO = 3
9
+ QUAD = 4
10
+ SURROUND = 5
11
+ FIVE_POINT_ONE = 6
12
+ SEVEN_POINT_ONE = 7
13
+ SEVEN_POINT_FOUR = 9
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,12 @@
1
+ module FMOD
2
+ module Core
3
+ class SpectrumData < Structure
4
+
5
+ def initialize(address = nil)
6
+ types = [TYPE_INT, TYPE_INT, [TYPE_FLOAT, 32]]
7
+ members = [:length, :channel_count, :spectrum]
8
+ super(address, types, members)
9
+ end
10
+ end
11
+ end
12
+ 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,14 @@
1
+ module FMOD
2
+ module Core
3
+ module TagDataType
4
+ BINARY = 0
5
+ INT = 1
6
+ FLOAT = 2
7
+ STRING = 3
8
+ STRING_UTF16 = 4
9
+ STRING_UTF16BE = 5
10
+ STRING_UTF8 = 6
11
+ CDTOC = 7
12
+ end
13
+ end
14
+ 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
@@ -0,0 +1,12 @@
1
+ module FMOD
2
+ module Core
3
+ module WindowType
4
+ RECT = 0
5
+ TRIANGLE = 1
6
+ HAMMING = 2
7
+ HANNING = 3
8
+ BLACKMAN = 4
9
+ BLACKMAN_HARRIS = 5
10
+ end
11
+ end
12
+ end
@@ -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