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,87 @@
1
+
2
+ module FMOD
3
+ module Effects
4
+
5
+ ##
6
+ # This unit implements SFX reverb.
7
+ #
8
+ # This is a high quality I3DL2 based reverb.
9
+ #
10
+ # On top of the I3DL2 property set, "Dry Level" is also included to allow
11
+ # the dry mix to be changed.
12
+ #
13
+ # @attr decay_time [Float] Reverberation decay time at low-frequencies in
14
+ # milliseconds.
15
+ # * *Minimum:* 100.0
16
+ # * *Maximum:* 20000.0
17
+ # * *Default:* 1500
18
+ # @attr early_delay [Float] Delay time of first reflection in milliseconds.
19
+ # * *Minimum:* 0.0
20
+ # * *Maximum:* 300.0
21
+ # * *Default:* 20.0
22
+ # @attr late_delay [Float] Late reverberation delay time relative to first
23
+ # reflection in milliseconds.
24
+ # * *Minimum:* 0.0
25
+ # * *Maximum:* 100.0
26
+ # * *Default:* 40.0
27
+ # @attr hf_reference [Float] Reference frequency for high-frequency decay in
28
+ # Hz.
29
+ # * *Minimum:* 20.0
30
+ # * *Maximum:* 20000.0
31
+ # * *Default:* 5000.0
32
+ # @attr hf_decay_ratio [Float] High-frequency decay time relative to decay
33
+ # time in percent.
34
+ # * *Minimum:* 10.0
35
+ # * *Maximum:* 100.0
36
+ # * *Default:* 50.0
37
+ # @attr diffusion [Float] Reverberation diffusion (echo density) in percent.
38
+ # * *Minimum:* 0.0
39
+ # * *Maximum:* 100.0
40
+ # * *Default:* 100.0
41
+ # @attr density [Float] Reverberation density (modal density) in percent.
42
+ # * *Minimum:* 0.0
43
+ # * *Maximum:* 100.0
44
+ # * *Default:* 100.0
45
+ # @attr low_shelf_frequency [Float] Transition frequency of low-shelf filter
46
+ # in Hz.
47
+ # * *Minimum:* 20.0
48
+ # * *Maximum:* 1000.0
49
+ # * *Default:* 250.0
50
+ # @attr low_shelf_gain [Float] Gain of low-shelf filter in dB.
51
+ # * *Minimum:* -36.0
52
+ # * *Maximum:* 12.0
53
+ # * *Default:* 0.0
54
+ # @attr high_cut [Float] Cutoff frequency of low-pass filter in Hz.
55
+ # * *Minimum:* 20.0
56
+ # * *Maximum:* 20000.0
57
+ # * *Default:* 20000.0
58
+ # @attr early_late_mix [Float] Blend ratio of late reverb to early
59
+ # reflections in percent.
60
+ # * *Minimum:* 0.0
61
+ # * *Maximum:* 100.0
62
+ # * *Default:* 50.0
63
+ # @attr wet_level [Float] Reverb signal level in dB.
64
+ # * *Minimum:* -80.0
65
+ # * *Maximum:* 20.0
66
+ # * *Default:* -6.0
67
+ # @attr dry_level [Float] Dry signal level in dB.
68
+ # * *Minimum:* -80.0
69
+ # * *Maximum:* 20.0
70
+ # * *Default:* 0.0
71
+ class SfxReverb < Dsp
72
+ float_param(0, :decay_time, min: 100.0, max: 20000.0)
73
+ float_param(0, :early_delay, min: 0.0, max: 300.0)
74
+ float_param(0, :late_delay, min: 0.0, max: 100.0)
75
+ float_param(0, :hf_reference, min: 20.0, max: 20000.0)
76
+ float_param(0, :hf_decay_ratio, min: 10.0, max: 100.0)
77
+ float_param(0, :diffusion, min: 0.0, max: 100.0)
78
+ float_param(0, :density, min: 0.0, max: 100.0)
79
+ float_param(0, :low_shelf_frequency, min: 20.0, max: 1000.0)
80
+ float_param(0, :low_shelf_gain, min: -36.0, max: 12.0)
81
+ float_param(0, :high_cut, min: 20.0, max: 20000.0)
82
+ float_param(0, :early_late_mix, min: 0.0, max: 100.0)
83
+ float_param(0, :wet_level, min: -80.0, max: 20.0)
84
+ float_param(0, :dry_level, min: -80.0, max: 20.0)
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,41 @@
1
+ module FMOD
2
+ module Effects
3
+
4
+ ##
5
+ # This unit is a three-band equalizer.
6
+ #
7
+ # @attr low_gain [Float] Low frequency gain in dB. .
8
+ # * *Minimum:* -80.0
9
+ # * *Maximum:* 10.0
10
+ # * *Default:* 0.0
11
+ # @attr mid_gain [Float] Mid frequency gain in dB.
12
+ # * *Minimum:* -80.0
13
+ # * *Maximum:* 10.0
14
+ # * *Default:* 0.0
15
+ # @attr high_gain [Float] High frequency gain in dB.
16
+ # * *Minimum:* -80.0
17
+ # * *Maximum:* 10.0
18
+ # * *Default:* 0.0
19
+ # @attr low_crossover [Float] Low-to-mid crossover frequency in Hz.
20
+ # * *Minimum:* 10.0
21
+ # * *Maximum:* 22000.0
22
+ # * *Default:* 4000.0
23
+ # @attr high_crossover [Float] Mid-to-high crossover frequency in Hz.
24
+ # * *Minimum:* 10.0
25
+ # * *Maximum:* 22000.0
26
+ # * *Default:* 4000.0
27
+ # @attr crossover_slope [Integer] Crossover slope.
28
+ # * *0:* 12dB/Octave
29
+ # * *1:* 24dB/Octave
30
+ # * *2:* 48dB/Octave
31
+ # * *Default:* 1 (24dB/Octave)
32
+ class ThreeEq < Dsp
33
+ float_param(0, :low_gain, min: -80.0, max: 10.0)
34
+ float_param(1, :mid_gain, min: -80.0, max: 10.0)
35
+ float_param(2, :high_gain, min: -80.0, max: 10.0)
36
+ float_param(3, :low_crossover, min: 10.0, max: 22000.0)
37
+ float_param(4, :high_crossover, min: 10.0, max: 22000.0)
38
+ integer_param(5, :crossover_slope, min: 0, max: 2)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,57 @@
1
+
2
+ module FMOD
3
+ module Effects
4
+
5
+ ##
6
+ # This unit "sends" and "receives" from a selection of up to 32 different
7
+ # slots. It is like a send/return but it uses global slots rather than
8
+ # returns as the destination. It also has other features. Multiple
9
+ # transceivers can receive from a single channel, or multiple transceivers
10
+ # can send to a single channel, or a combination of both.
11
+ #
12
+ # The transceiver only transmits and receives to a global array of 32
13
+ # channels. The transceiver can be set to receiver mode (like a {Return})
14
+ # and can receive the signal at a variable {#gain}. The transceiver can also
15
+ # be set to transmit to a channel (like a {Send}) and can transmit the
16
+ # signal with a variable {#gain}.
17
+ #
18
+ # The {#speaker_mode} is only applicable to the transmission format, not the
19
+ # receive format. This means this parameter is ignored in "receive mode".
20
+ # This allows receivers to receive at the speaker mode of the user's choice.
21
+ # Receiving from a mono channel, is cheaper than receiving from a surround
22
+ # channel for example. The 3 speaker modes {SpeakerMode::MONO},
23
+ # {SpeakerMode::STEREO}, {SpeakerMode::SURROUND} are stored as separate
24
+ # buffers in memory for a transmitter channel. To save memory, use 1 common
25
+ # speaker mode for a transmitter.
26
+ #
27
+ # The transceiver is double buffered to avoid de-syncing of transmitters and
28
+ # receivers. This means there will be a 1 block delay on a receiver,
29
+ # compared to the data sent from a transmitter.
30
+ #
31
+ # Multiple transmitters sending to the same channel will be mixed together.
32
+ #
33
+ # @attr transmit [Boolean] The behavior of the unit.
34
+ # * *false:* Transceiver is a "receiver" (like a {Return}) and accepts
35
+ # data from a channel.
36
+ # * *true:* Transceiver is a "transmitter" (like a {Send}).
37
+ # * *Default:* +false+
38
+ # @attr gain [Float] Gain to receive or transmit at in dB.
39
+ # * *Minimum:* -80.0
40
+ # * *Maximum:* 10.0
41
+ # * *Default:* 0.0
42
+ # @attr channel [Integer] Integer to select current global slot, shared by
43
+ # all Transceivers, that can be transmitted to or received from.
44
+ # * *Minimum:* 0
45
+ # * *Maximum:* 31
46
+ # * *Default:* 0
47
+ # @attr speaker_mode [Integer] Speaker mode (transmitter mode only).
48
+ # * *Default:* {SpeakerMode::DEFAULT}
49
+ # @see SpeakerMode
50
+ class Transceiver < Dsp
51
+ bool_param(0, :transmit)
52
+ float_param(1, :gain, min: -80.0, max: 10.0)
53
+ integer_param(2, :channel, min: 0, max: 31)
54
+ integer_param(3, :speaker_mode, min: 0, max: 9)
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,67 @@
1
+
2
+ module FMOD
3
+ module Effects
4
+
5
+ ##
6
+ # This unit produces a tremolo / chopper effect on the sound.
7
+ #
8
+ # The tremolo effect varies the amplitude of a sound. Depending on the
9
+ # settings, this unit can produce a tremolo, chopper or auto-pan effect.
10
+ #
11
+ # The shape of the LFO (low freq. oscillator) can morphed between sine,
12
+ # triangle and sawtooth waves using the {#shape} and {#skew} parameters.
13
+ #
14
+ # {#duty} and {#square} are useful for a chopper-type effect where the first
15
+ # controls the on-time duration and second controls the flatness of the
16
+ # envelope.
17
+ #
18
+ # {#spread} varies the LFO phase between channels to get an auto-pan effect.
19
+ # This works best with a sine shape LFO.
20
+ #
21
+ # The LFO can be synchronized using the {#phase} parameter which sets its
22
+ # instantaneous phase.
23
+ #
24
+ # @attr frequency [Float] LFO frequency in Hz.
25
+ # * *Minimum:* 0.1
26
+ # * *Maximum:* 20.0
27
+ # * *Default:* 5.0
28
+ # @attr depth [Float] Tremolo depth.
29
+ # * *Minimum:* 0.0
30
+ # * *Maximum:* 1.0
31
+ # * *Default:* 1.0
32
+ # @attr shape [Float] LFO shape morph between triangle and sine.
33
+ # * *Minimum:* 0.0
34
+ # * *Maximum:* 1.0
35
+ # * *Default:* 0.0
36
+ # @attr skew [Float] Time-skewing of LFO cycle.
37
+ # * *Minimum:* -1.0
38
+ # * *Maximum:* 1.0
39
+ # * *Default:* 0.0
40
+ # @attr duty [Float] LFO on-time. 0 to 1.
41
+ # * *Minimum:* 0.0
42
+ # * *Maximum:* 1.0
43
+ # * *Default:* 0.5
44
+ # @attr square [Float] Flatness of the LFO shape.
45
+ # * *Minimum:* 0.0
46
+ # * *Maximum:* 1.0
47
+ # * *Default:* 0.0
48
+ # @attr phase [Float] Instantaneous LFO phase.
49
+ # * *Minimum:* 0.0
50
+ # * *Maximum:* 1.0
51
+ # * *Default:* 0.0
52
+ # @attr spread [Float] Rotation / auto-pan effect.
53
+ # * *Minimum:* -1.0
54
+ # * *Maximum:* 1.0
55
+ # * *Default:* 0.0
56
+ class Tremolo < Dsp
57
+ float_param(0, :frequency, min: 0.1, max: 20.0)
58
+ float_param(1, :depth, min: 0.0, max: 1.0)
59
+ float_param(2, :shape, min: 0.0, max: 1.0)
60
+ float_param(3, :skew, min: -1.0, max: 1.0)
61
+ float_param(4, :duty, min: 0.0, max: 1.0)
62
+ float_param(5, :square, min: 0.0, max: 1.0)
63
+ float_param(6, :phase, min: 0.0, max: 1.0)
64
+ float_param(7, :spread, min: -1.0, max: 1.0)
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,12 @@
1
+
2
+ module FMOD
3
+ module Effects
4
+
5
+ ##
6
+ # This unit allows the use of Steinberg VST plugins.
7
+ #
8
+ # @note Must sub-class to provide functionality.
9
+ class VstPlugin < Dsp
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+
2
+ module FMOD
3
+ module Effects
4
+
5
+ ##
6
+ # This unit allows the use of Nullsoft Winamp plugins
7
+ #
8
+ # @note Must sub-class to provide functionality.
9
+ class WinampPlugin < Dsp
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,108 @@
1
+ module FMOD
2
+ class Error < StandardError
3
+
4
+ include FMOD::Core
5
+
6
+ ##
7
+ # @overload initialize(code)
8
+ # @param code [Integer]
9
+ # @overload initialize(message)
10
+ # @param message [String]
11
+ def initialize(code)
12
+ message = code.is_a?(Integer) ? self.class.error_string(code) : code
13
+ super(message)
14
+ end
15
+
16
+ ##
17
+ # Retrieves a generic message for the specified result code.
18
+ # @param code [Integer] An FMOD generated error code.
19
+ # @return [String] A generic error message.
20
+ # @see Result
21
+ def self.error_string(code)
22
+ case code
23
+ when Result::BAD_COMMAND then "Tried to call a function on a data type that does not allow this type of functionality (ie calling Sound::lock on a streaming sound)."
24
+ when Result::CHANNEL_ALLOC then "Error trying to allocate a channel."
25
+ when Result::CHANNEL_STOLEN then "The specified channel has been reused to play another sound."
26
+ when Result::DMA then "DMA Failure. See debug output for more information."
27
+ when Result::DSP_CONNECTION then "DSP connection error. Connection possibly caused a cyclic dependency or connected dsps with incompatible buffer counts."
28
+ when Result::DSP_DONT_PROCESS then "DSP return code from a DSP process query callback. Tells mixer not to call the process callback and therefore not consume CPU. Use this to optimize the DSP graph. "
29
+ when Result::DSP_FORMAT then "DSP Format error. A DSP unit may have attempted to connect to this network with the wrong format, or a matrix may have been set with the wrong size if the target unit has a specified channel map."
30
+ when Result::DSP_IN_USE then "DSP is already in the mixer's DSP network. It must be removed before being reinserted or released."
31
+ when Result::DSP_NOT_FOUND then "DSP connection error. Couldn't find the DSP unit specified."
32
+ when Result::DSP_RESERVED then "DSP operation error. Cannot perform operation on this DSP as it is reserved by the system."
33
+ when Result::DSP_SILENCE then "DSP return code from a DSP process query callback. Tells mixer silence would be produced from read, so go idle and not consume CPU. Use this to optimize the DSP graph."
34
+ when Result::DSP_TYPE then "DSP operation cannot be performed on a DSP of this type. "
35
+ when Result::FILE_BAD then "Error loading file."
36
+ when Result::FILE_COULD__SEEK then "Couldn't perform seek operation. This is a limitation of the medium (ie netstreams) or the file format."
37
+ when Result::FILE_DISK_EJECTED then "Media was ejected while reading."
38
+ when Result::FILE_EOF then "End of file unexpectedly reached while trying to read essential data (truncated?)."
39
+ when Result::FILE_END_OF_DATA then "End of current chunk reached while trying to read data. "
40
+ when Result::FILE_NOT_FOUND then "File not found."
41
+ when Result::FORMAT then "Unsupported file or audio format."
42
+ when Result::HEADER_MISMATCH then "There is a version mismatch between the FMOD header and either the FMOD Studio library or the FMOD Low Level library."
43
+ when Result::HTTP then " HTTP error occurred. This is a catch-all for HTTP errors not listed elsewhere."
44
+ when Result::HTTP_ACCESS then "The specified resource requires authentication or is forbidden."
45
+ when Result::HTTP_PROXY_AUTH then "Proxy authentication is required to access the specified resource. "
46
+ when Result::HTTP_SERVER_ERROR then "A HTTP server error occurred."
47
+ when Result::HTTP_TIMEOUT then "The HTTP request timed out. "
48
+ when Result::INITIALIZATION then "FMOD was not initialized correctly to support this function. "
49
+ when Result::INITIALIZED then "Cannot call this command after System::new."
50
+ when Result::INTERNAL then "An error occurred that wasn't supposed to. Contact support."
51
+ when Result::INVALID_FLOAT then "Value passed in was a NaN, Inf or denormalized float."
52
+ when Result::INVALID_HANDLE then "An invalid object handle was used."
53
+ when Result::INVALID_PARAM then "An invalid parameter was passed to this function."
54
+ when Result::INVALID_POSITION then "An invalid seek position was passed to this function."
55
+ when Result::INVALID_SPEAKER then "An invalid speaker was passed to this function based on the current speaker mode. "
56
+ when Result::INVALID_SYNC_POINT then "The syncpoint did not come from this sound handle."
57
+ when Result::INVALID_THREAD then "Tried to call a function on a thread that is not supported."
58
+ when Result::INVALID_VECTOR then "The vectors passed in are not unit length, or perpendicular."
59
+ when Result::MAX_AUDIBLE then "Reached maximum audible playback count for this sound's soundgroup."
60
+ when Result::MEMORY then "Not enough memory or resources."
61
+ when Result::MEMORY_CANT_POINT then "Can't use OPEN_MEMORY_POINT on non-PCM source data, or non mp3/xma/adpcm data if CREATE_COMPRESSED_SAMPLE was used."
62
+ when Result::NEEDS_3D then "Tried to call a command on a 2d sound when the command was meant for 3d sound."
63
+ when Result::NEEDS_HARDWARE then "Tried to use a feature that requires hardware support."
64
+ when Result::NET_CONNECT then "Couldn't connect to the specified host."
65
+ when Result::NET_SOCKET_ERROR then "A socket error occurred. This is a catch-all for socket-related errors not listed elsewhere."
66
+ when Result::NET_URL then "The specified URL couldn't be resolved."
67
+ when Result::NET_WOULD_BLOCK then "Operation on a non-blocking socket could not complete immediately. "
68
+ when Result::NOT_READY then "Operation could not be performed because specified sound/DSP connection is not ready."
69
+ when Result::OUTPUT_ALLOCATED then "Error initializing output device, but more specifically, the output device is already in use and cannot be reused."
70
+ when Result::OUTPUT_CREATE_BUFFER then "Error creating hardware sound buffer."
71
+ when Result::OUTPUT_DRIVER_CALL then "A call to a standard soundcard driver failed, which could possibly mean a bug in the driver or resources were missing or exhausted."
72
+ when Result::OUTPUT_FORMAT then "Soundcard does not support the specified format."
73
+ when Result::OUTPUT_INIT then "Error initializing output device."
74
+ when Result::OUTPUT_NO_DRIVERS then "The output device has no drivers installed. If pre-init, OUTPUT_NO_SOUND is selected as the output mode. If post-init, the function just fails."
75
+ when Result::PLUGIN then "An unspecified error has been returned from a plugin."
76
+ when Result::PLUGIN_MISSING then "A requested output, dsp unit type or codec was not available."
77
+ when Result::PLUGIN_RESOURCE then "A resource that the plugin requires cannot be found. (ie the DLS file for MIDI playback)"
78
+ when Result::PLUGIN_VERSION then "A plugin was built with an unsupported SDK version."
79
+ when Result::RECORD then "An error occurred trying to initialize the recording device."
80
+ when Result::REVERB_CHANNEL_GROUP then "Reverb properties cannot be set on this channel because a parent channelgroup owns the reverb connection."
81
+ when Result::REVERB_INSTANCE then "Specified instance in ReverbProperties couldn't be set. Most likely because it is an invalid instance number or the reverb doesn't exist"
82
+ when Result::SUBSOUNDS then "The error occurred because the sound referenced contains subsounds when it shouldn't have, or it doesn't contain subsounds when it should have. The operation may also not be able to be performed on a parent sound."
83
+ when Result::SUBSOUND_ALLOCATED then "This subsound is already being used by another sound, you cannot have more than one parent to a sound. Null out the other parent's entry first."
84
+ when Result::SUBSOUND_CANT_MOVE then "Shared subsounds cannot be replaced or moved from their parent stream, such as when the parent stream is an FSB file."
85
+ when Result::TAG_NOT_FOUND then "The specified tag could not be found or there are no tags."
86
+ when Result::TOO_MANY_CHANNELS then "The sound created exceeds the allowable input channel count. This can be increased using the 'maxinputchannels' parameter in System::setSoftwareFormat."
87
+ when Result::TRUNCATED then "The retrieved string is too long to fit in the supplied buffer and has been truncated."
88
+ when Result::UNIMPLEMENTED then "Something in FMOD hasn't been implemented when it should be! contact support!"
89
+ when Result::UNINITIALIZED then "This command failed because System::new or System::set_driver was not called."
90
+ when Result::UNSUPPORTED then "A command issued was not supported by this object. Possibly a plugin without certain callbacks specified"
91
+ when Result::VERSION then "The version number of this file format is not supported."
92
+ when Result::EVENT_ALREADY_LOADED then "The specified bank has already been loaded."
93
+ when Result::EVENT_LIVE_UPDATE_BUSY then "The live update connection failed due to the game already being connected."
94
+ when Result::EVENT_LIVE_UPDATE_MISMATCH then "The live update connection failed due to the game data being out of sync with the tool."
95
+ when Result::EVENT_LIVE_UPDATE_TIMEOUT then "The live update connection timed out."
96
+ when Result::EVENT_NOT_FOUND then "The requested event, bus or vca could not be found."
97
+ when Result::STUDIO_UNINITIALIZED then "The Studio::System object is not yet initialized."
98
+ when Result::STUDIO_NOT_LOADED then "The specified resource is not loaded, so it can't be unloaded."
99
+ when Result::INVALID_STRING then "An invalid string was passed to this function."
100
+ when Result::ALREADY_LOCKED then "The specified resource is already locked."
101
+ when Result::NOT_LOCKED then "The specified resource is not locked, so it can't be unlocked."
102
+ when Result::RECORD_DISCONNECTED then "The specified recording driver has been disconnected."
103
+ when Result::TOO_MANY_SAMPLES then "The length provided exceeds the allowable limit."
104
+ else "Unknown error. Code: #{code}"
105
+ end
106
+ end
107
+ end
108
+ end
@@ -0,0 +1,380 @@
1
+
2
+ module FMOD
3
+ class Geometry < Handle
4
+
5
+ include Enumerable
6
+
7
+ ##
8
+ # @!attribute active
9
+ # Value indicating if object will be processed in the geometry engine.
10
+ #
11
+ # @return [Boolean]
12
+ bool_reader(:active, :Geometry_GetActive)
13
+ bool_writer(:active=, :Geometry_SetActive)
14
+
15
+ ##
16
+ # @!attribute polygon_count
17
+ # Retrieves the number of polygons stored within this {Geometry} object.
18
+ #
19
+ # @return [Integer]
20
+ integer_reader(:polygon_count, :Geometry_GetNumPolygons)
21
+
22
+ alias size polygon_count
23
+
24
+ ##
25
+ # @!attribute position
26
+ # The position of the object in world space, which is the same space FMOD
27
+ # sounds and listeners reside in.
28
+ #
29
+ # @return [Vector]
30
+
31
+ def position
32
+ FMOD.invoke(:Geometry_GetPosition, self, vector = Vector.zero)
33
+ vector
34
+ end
35
+
36
+ def position=(vector)
37
+ FMOD.type?(vector, Vector)
38
+ FMOD.invoke(:Geometry_SetPosition, self, vector)
39
+ end
40
+
41
+ ##
42
+ # @!attribute scale
43
+ # The relative scale vector of the geometry object. An object can be
44
+ # scaled/warped in all 3 dimensions separately using the vector without
45
+ # having to modify polygon data.
46
+ # * *Default:* {Vector.one}
47
+ #
48
+ # @return [Vector]
49
+
50
+ def scale
51
+ FMOD.invoke(:Geometry_GetScale, self, vector = Vector.zero)
52
+ vector
53
+ end
54
+
55
+ def scale=(vector)
56
+ FMOD.type?(vector, Vector)
57
+ FMOD.invoke(:Geometry_SetScale, self, vector)
58
+ end
59
+
60
+ ##
61
+ # @!attribute rotation
62
+ # The current orientation of the geometry object.
63
+ #
64
+ # @return [Rotation]
65
+ # @see rotate
66
+
67
+ def rotation
68
+ forward, up = Vector.zero, Vector.zero
69
+ FMOD.invoke(:Geometry_GetRotation, self, forward, up)
70
+ Rotation.new(forward, up)
71
+ end
72
+
73
+ def rotation=(rotation)
74
+ FMOD.type?(rotation, Rotation)
75
+ rotate(*rotation.values)
76
+ end
77
+
78
+ ##
79
+ # Sets the orientation of the geometry object.
80
+ # @param forward [Vector] The forwards orientation of the geometry object.
81
+ # This vector must be of unit length and perpendicular to the upward
82
+ # vector. You can specify +nil+ to not update the forwards orientation of
83
+ # the geometry object.
84
+ # @param upward [Vector] The upwards orientation of the geometry object.
85
+ # This vector must be of unit length and perpendicular to the forward
86
+ # vector. You can specify +nil+ to not update the upwards orientation of
87
+ # the geometry object.
88
+ def rotate(forward, upward)
89
+ FMOD.type?(forward, Vector) unless forward.nil?
90
+ FMOD.type?(upward, Vector) unless upward.nil?
91
+ FMOD.invoke(:Geometry_SetRotation, self, forward, upward)
92
+ end
93
+
94
+ ##
95
+ # Retrieves the maximum number of polygons allocatable for this object.
96
+ #
97
+ # This is not the number of polygons currently present.
98
+ #
99
+ # @return [Integer]
100
+ def max_polygons
101
+ max = "\0" * SIZEOF_INT
102
+ FMOD.invoke(:Geometry_GetMaxPolygons, self, max, nil)
103
+ max.unpack1('l')
104
+ end
105
+
106
+ # Retrieves the maximum number of vertices allocatable for this object.
107
+ #
108
+ # This is not the number of vertices currently present.
109
+ #
110
+ # @return [Integer]
111
+ def max_vertices
112
+ max = "\0" * SIZEOF_INT
113
+ FMOD.invoke(:Geometry_GetMaxPolygons, self, nil, max)
114
+ max.unpack1('l')
115
+ end
116
+
117
+ ##
118
+ # Retrieves the {Polygon} at the specified index.
119
+ # @param index [Integer] The index of the Polygon to retrieve.
120
+ # @return [Polygon]
121
+ def [](index)
122
+ return nil unless index.between?(0, polygon_count)
123
+ Polygon.send(:new, self, index)
124
+ end
125
+
126
+ ##
127
+ # Adds a polygon to an geometry object.
128
+ #
129
+ # @note A minimum of 3 vertices is required to create a {Polygon}.
130
+ #
131
+ # @param vertices [Array<Vector>] array of vertices located in object space.
132
+ # @param direct [Float] Occlusion value which affects volume or audible
133
+ # frequencies.
134
+ # * *Minimum:* 0.0 The polygon does not occlude volume or audible
135
+ # frequencies (sound will be fully audible)
136
+ # * *Maximum:* 1.0 The polygon fully occludes (sound will be silent)
137
+ # @param reverb [Float] Occlusion value from 0.0 to 1.0 which affects the
138
+ # reverb mix.
139
+ # * *Minimum:* 0.0 The polygon does not occlude reverb (reverb reflections
140
+ # still travel through this polygon)
141
+ # * *Maximum:* 1.0 The polygon fully occludes reverb (reverb reflections
142
+ # will be silent through this polygon).
143
+ # @param double_sided [Boolean] Description of polygon if it is double sided
144
+ # or single sided.
145
+ # * *true:* Polygon is double sided
146
+ # * *false:* Polygon is single sided, and the winding of the polygon
147
+ # (which determines the polygon's normal) determines which side of the
148
+ # polygon will cause occlusion.
149
+ def add_polygon(vertices, direct = 0.0, reverb = 0.0, double_sided = false)
150
+ size = vertices.size
151
+ unless size >= 3
152
+ message = "3 or more vertices required for polygon: #{size} specified"
153
+ raise ArgumentError, message
154
+ end
155
+ vectors = vertices.map(&:to_str).join
156
+ direct = direct.clamp(0.0, 1.0)
157
+ reverb = reverb.clamp(0.0, 1.0)
158
+ FMOD.invoke(:Geometry_AddPolygon, self, direct, reverb,
159
+ double_sided.to_i, size, vectors, index = "\0" * SIZEOF_INT)
160
+ Polygon.send(:new, self, index.unpack1('l'))
161
+ end
162
+
163
+ ##
164
+ # Serializes the {Geometry} object into a binary block.
165
+ #
166
+ # @overload save(filename)
167
+ # @param filename [String] A filename where object will be saved to.
168
+ # @return [Boolean] +true+ if object was successfully flushed to disk,
169
+ # otherwise +false+.
170
+ # @overload save
171
+ # Serializes the {Geometry} object and returns the data as a binary
172
+ # string.
173
+ # @return [String]
174
+ # @see System.load_geometry
175
+ def save(filename = nil)
176
+ FMOD.invoke(:Geometry_Save, self, nil, size = "\0" * SIZEOF_INT)
177
+ data = "\0" * size.unpack1('l')
178
+ FMOD.invoke(:Geometry_Save, self, data, size)
179
+ unless filename.nil?
180
+ File.open(filename, 'wb') { |file| file.write(data) } rescue return false
181
+ return true
182
+ end
183
+ data
184
+ end
185
+
186
+ ##
187
+ # Enumerates the polygons contained within the {Geometry}.
188
+ #
189
+ # @overload each
190
+ # When called with block, yields each {Polygon} within the object before
191
+ # returning self.
192
+ # @yield [polygon] Yields a polygon to the block.
193
+ # @yieldparam polygon [Polygon] The current enumerated polygon.
194
+ # @return [self]
195
+ # @overload each
196
+ # When no block specified, returns an Enumerator for the {Geometry}.
197
+ # @return [Enumerator]
198
+ def each
199
+ return to_enum(:each) unless block_given?
200
+ (0...polygon_count).each { |i| yield self[i] }
201
+ self
202
+ end
203
+
204
+ ##
205
+ # Retrieves an array of {Polygon} objects within this {Geometry}.
206
+ # @return [Array<Polygon>]
207
+ def polygons
208
+ (0...polygon_count).map { |i| self[i] }
209
+ end
210
+
211
+ ##
212
+ # Describes the orientation of a geometry object.
213
+ # @attr forward [Vector] The forwards orientation of the geometry object.
214
+ # This vector must be of unit length and perpendicular to the {#up}
215
+ # vector. You can specify +nil+ to not update the forwards orientation of
216
+ # the geometry object.
217
+ # @attr up [Vector] The upwards orientation of the geometry object. This
218
+ # vector must be of unit length and perpendicular to the {#forward}
219
+ # vector. You can specify +nil+ to not update the upwards orientation of
220
+ # the geometry object.
221
+ Rotation = Struct.new(:forward, :up)
222
+
223
+ ##
224
+ # @abstract
225
+ # Wrapper class for a polygon within a {Geometry} object.
226
+ class Polygon
227
+
228
+ include Enumerable
229
+
230
+ private_class_method :new
231
+
232
+ ##
233
+ # The parent geometry object.
234
+ # @return [Geometry]
235
+ attr_reader :geometry
236
+
237
+ ##
238
+ # The index of the {Polygon} within its parent {Geometry} object.
239
+ # @return [Integer]
240
+ attr_reader :index
241
+
242
+ ##
243
+ # Creates a new instance of a Polygon object.
244
+ # @note Polygon objects should not be created by the user, only through
245
+ # {Geometry.add_polygon}, as they are an abstract wrapper only, not
246
+ # backed by an actual object.
247
+ # @param geometry [Geometry] The parent geometry object.
248
+ # @param index [Integer] The index of the polygon within the geometry.
249
+ # @api private
250
+ def initialize(geometry, index)
251
+ @geometry, @index = geometry, index
252
+ end
253
+
254
+ ##
255
+ # @!attribute direct_occlusion
256
+ # The occlusion value from 0.0 to 1.0 which affects volume or audible
257
+ # frequencies.
258
+ # * *Minimum:* 0.0 The polygon does not occlude volume or audible
259
+ # frequencies (sound will be fully audible)
260
+ # * *Maximum:* 1.0 The polygon fully occludes (sound will be silent)
261
+ #
262
+ # @return [Float]
263
+
264
+ def direct_occlusion
265
+ occlusion = "\0" * Fiddle::SIZEOF_FLOAT
266
+ FMOD.invoke(:Geometry_GetPolygonAttributes, @geometry, @index,
267
+ occlusion, nil, nil)
268
+ occlusion.unpack1('f')
269
+ end
270
+
271
+ def direct_occlusion=(occlusion)
272
+ FMOD.invoke(:Geometry_SetPolygonAttributes, @geometry, @index,
273
+ occlusion.clamp(0.0, 1.0), reverb_occlusion, double_sided.to_i)
274
+ end
275
+
276
+ ##
277
+ # @!attribute reverb_occlusion
278
+ # The occlusion value from 0.0 to 1.0 which affects the reverb mix.
279
+ # * *Minimum:* 0.0 The polygon does not occlude reverb (reverb
280
+ # reflections still travel through this polygon)
281
+ # * *Maximum:* 1.0 The polygon fully occludes reverb (reverb
282
+ # reflections will be silent through this polygon)
283
+ #
284
+ # @return [Float]
285
+
286
+ def reverb_occlusion
287
+ occlusion = "\0" * Fiddle::SIZEOF_FLOAT
288
+ FMOD.invoke(:Geometry_GetPolygonAttributes, @geometry, @index,
289
+ nil, occlusion, nil)
290
+ occlusion.unpack1('f')
291
+ end
292
+
293
+ def reverb_occlusion=(occlusion)
294
+ FMOD.invoke(:Geometry_SetPolygonAttributes, @geometry, @index,
295
+ direct_occlusion, occlusion.clamp(0.0, 1.0), double_sided.to_i)
296
+ end
297
+
298
+ ##
299
+ # @!attribute double_sided
300
+ # The description of polygon if it is double sided or single sided.
301
+ # * *true:* The polygon is double sided
302
+ # * *false:* The polygon is single sided, and the winding of the polygon
303
+ # (which determines the polygon's normal) determines which side of the
304
+ # polygon will cause occlusion.
305
+ #
306
+ # @return [Boolean]
307
+
308
+ def double_sided
309
+ double = "\0" * Fiddle::SIZEOF_INT
310
+ FMOD.invoke(:Geometry_GetPolygonAttributes, @geometry, @index,
311
+ nil, nil, double)
312
+ double.unpack1('l') != 0
313
+ end
314
+
315
+ def double_sided=(double_sided)
316
+ FMOD.invoke(:Geometry_SetPolygonAttributes, @geometry, @index,
317
+ direct_occlusion, reverb_occlusion, double_sided.to_i)
318
+ end
319
+
320
+ ##
321
+ # Retrieves the number of vertices within the polygon.
322
+ # @return [Integer]
323
+ def vertex_count
324
+ count = "\0" * Fiddle::SIZEOF_INT
325
+ FMOD.invoke(:Geometry_GetPolygonNumVertices, @geometry, @index, count)
326
+ count.unpack1('l')
327
+ end
328
+
329
+ alias size vertex_count
330
+
331
+ ##
332
+ # Retrieves the vertex of the polygon at the specified index.
333
+ # @param index [Integer] The index of the vertex to retrieve.
334
+ # @return [Vector]
335
+ def [](index)
336
+ return nil unless index.between?(0, vertex_count - 1)
337
+ vertex = Vector.zero
338
+ FMOD.invoke(:Geometry_GetPolygonVertex, @geometry, @index, index, vertex)
339
+ vertex
340
+ end
341
+
342
+ ##
343
+ # Sets the vertex of the polygon at the specified index.
344
+ # @param index [Integer] The index of the vertex to set.
345
+ # @param vertex [Vector] The vertex to set.
346
+ # @return [Vector] The vertex.
347
+ def []=(index, vertex)
348
+ unless index.between?(0, vertex_count - 1)
349
+ message = "Index #{index} outside of bounds: 0...#{vertex.count}"
350
+ raise IndexError, message
351
+ end
352
+ FMOD.type?(vertex, Vector)
353
+ FMOD.invoke(:Geometry_SetPolygonVertex, @geometry, @index, index, vertex)
354
+ end
355
+
356
+ ##
357
+ # @overload each
358
+ # When called with a block, yields each vertex in turn before returning
359
+ # self.
360
+ # @yield [vertex] Yields a vertex to the block.
361
+ # @yieldparam vertex [Vector] The enumerated vertex.
362
+ # @return [self]
363
+ # @overload each
364
+ # Returns an Enumerator for the polygon.
365
+ # @return [Enumerator]
366
+ def each
367
+ return to_enum(:each) unless block_given?
368
+ (0...vertex_count).each { |i| yield self[i] }
369
+ self
370
+ end
371
+
372
+ ##
373
+ # Retrieves an array of the vertices within the polygon.
374
+ # @return [Array<Vector>]
375
+ def vertices
376
+ (0...vertex_count).map { |i| self[i] }
377
+ end
378
+ end
379
+ end
380
+ end