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.
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