lib/fmod/system.rb in fmod-0.9.1 vs lib/fmod/system.rb in fmod-0.9.2

- old
+ new

@@ -1,22 +1,82 @@ module FMOD + + ## + # The primary central class of FMOD. This class acts as a factory for creation + # of other core FMOD objects, and a centralized control interface. All core + # FMOD objects belong to a System object. class System < Handle + ## + # Contains values for describing the current CPU time used by FMOD. + # + # @attr dsp [Float] The current DSP mixing engine CPU usage. Result will be + # from 0.0 to 100.0. + # @attr stream [Float] The current streaming engine CPU usage. Result will + # be from 0.0 to 100.0. + # @attr geometry [Float] The current geometry engine CPU usage. Result will + # be from 0.0 to 100.0. + # @attr update [Float] The current System::update CPU usage. Result will be + # from 0.0 to 100.0. + # @attr total [Float] The current total CPU usage. Result will be from 0 to + # 100.0. CpuUsage = Struct.new(:dsp, :stream, :geometry, :update, :total) + ## + # Contains the amount of dedicated sound ram available if the platform + # supports it. + # @attr current [Integer] The currently allocated sound RAM memory at time + # of call. + # @attr max [Integer] The maximum allocated sound RAM memory since the + # System was created. + # @attr total [Integer] The total amount of sound RAM available on this + # device. RamUsage = Struct.new(:current, :max, :total) + ## + # Contains information about file reads by FMOD. + # @attr sample [Integer] The total bytes read from file for loading + # sample data. + # @attr stream [Integer] The total bytes read from file for streaming + # sounds. + # @attr other [Integer] The total bytes read for non-audio data such + # as FMOD Studio banks. FileUsage = Struct.new(:sample, :stream, :other) + # Represents a logical position of a speaker. + # @attr index [Integer] The index of the speaker. + # @attr x [Float] The x-coordinate of the speaker. + # @attr y [Float] The y-coordinate of the speaker. + # @attr active [Boolean] +true+ if speaker will be enabled, + # otherwise +false+. Speaker = Struct.new(:index, :x, :y, :active) + ## + # Defines the information to display for the selected plugin. + # @attr handle [Integer] The plugin handle. + # @attr type [Integer] The type of the plugin. + # @attr name [String] The name of the plugin. + # @attr version [Integer] The version number set by the plugin. Plugin = Struct.new(:handle, :type, :name, :version) + # Describes the output format for the software mixer. + # @attr sample_rate [Integer] The rate in Hz, that the software mixer will + # run at. Specify values between 8000 and 192000. + # @attr speaker_mode [Integer] Speaker setup for the software mixer. + # @attr raw_channels [Integer] Number of output channels / speakers to + # initialize the sound card to in raw speaker mode. SoftwareFormat = Struct.new(:sample_rate, :speaker_mode, :raw_channels) + ## + # The buffer size settings for the FMOD software mixing engine. + # @attr size [Integer] The mixer engine block size in samples. Default is + # 1024. (milliseconds = 1024 at 48khz = 1024 / 48000 * 1000 = 10.66ms). + # @attr count [Integer] The mixer engine number of buffers used. Default is + # 4. To get the total buffer size multiply the buffer length by the number + # of buffers. By default this would be 4*1024. DspBuffer = Struct.new(:size, :count) ## # The internal buffer size for streams opened after this call. Larger values # will consume more memory, whereas smaller values may cause buffer @@ -26,11 +86,14 @@ # @attr size [Integer] The size of stream file buffer. Default is 16384. # @attr type [Integer] Type of unit for stream file buffer size. # @see TimeUnit StreamBuffer = Struct.new(:size, :type) - def initialize(handle) + ## + # @param address [Pointer, Integer, String] The address of a native FMOD + # pointer. + def initialize(address) super @rolloff_callbacks = [] sig = [TYPE_VOIDP, TYPE_FLOAT] abi = FMOD::ABI cb = Closure::BlockCaller.new(TYPE_FLOAT, sig, abi) do |channel, distance| @@ -41,10 +104,17 @@ distance end FMOD.invoke(:System_Set3DRolloffCallback, self, cb) end + ## + # When FMOD wants to calculate 3D volume for a channel, this callback can be + # used to override the internal volume calculation based on distance. + # + # @param proc [Proc] Proc to call. Optional, must give block if nil. + # @yield [index] The block to call when rolloff is calculated. + # @return [void] def on_rolloff(proc = nil, &block) cb = proc || block raise LocalJumpError, "No block given." if cb.nil? @rolloff_callbacks << cb end @@ -875,46 +945,15 @@ self end # @!endgroup + # @!group Network + # @!attribute network_proxy + # @return [String] proxy server to use for internet connections. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - def network_proxy buffer = "\0" * 512 FMOD.invoke(:System_GetNetworkProxy, self, buffer, 512) # noinspection RubyResolve buffer.delete("\0").force_encoding(Encoding::UTF_8) @@ -923,134 +962,18 @@ def network_proxy=(url) # noinspection RubyResolve FMOD.invoke(:System_SetNetworkProxy, self, url.encode(Encoding::UTF_8)) end + # @!attribute network_timeout + # @return [Integer] the timeout, in milliseconds, for network streams. integer_reader(:network_timeout, :System_GetNetworkTimeout) integer_writer(:network_timeout=, :System_SetNetworkTimeout) - integer_reader(:software_channels, :System_GetSoftwareChannels) - integer_writer(:software_channels=, :System_SetSoftwareChannels, 0, 64) + # @!endgroup - - - def master_channel_group - FMOD.invoke(:System_GetMasterChannelGroup, self, group = int_ptr) - ChannelGroup.new(group) - end - - def master_sound_group - FMOD.invoke(:System_GetMasterSoundGroup, self, group = int_ptr) - SoundGroup.new(group) - end - - - def update - FMOD.invoke(:System_Update, self) - end - ## - # Closes the {System} object without freeing the object's memory, so the - # system handle will still be valid. - # - # Closing the output renders objects created with this system object - # invalid. Make sure any sounds, channel groups, geometry and DSP objects - # are released before closing the system object. - # - # @return [void] - def close - FMOD.invoke(:System_Close, self) - end - - ## - # @!attribute [r] version - # @return [String] the current version of FMOD being used. - def version - FMOD.invoke(:System_GetVersion, self, version = "\0" * SIZEOF_INT) - FMOD.uint2version(version) - end - - ## - # Plays a sound object on a particular channel and {ChannelGroup}. - # - # When a sound is played, it will use the sound's default frequency and - # priority. - # - # A sound defined as {Mode::THREE_D} will by default play at the position of - # the listener. - # - # Channels are reference counted. If a channel is stolen by the FMOD - # priority system, then the handle to the stolen voice becomes invalid, and - # Channel based commands will not affect the new sound playing in its place. - # If all channels are currently full playing a sound, FMOD will steal a - # channel with the lowest priority sound. If more channels are playing than - # are currently available on the sound-card/sound device or software mixer, - # then FMOD will "virtualize" the channel. This type of channel is not - # heard, but it is updated as if it was playing. When its priority becomes - # high enough or another sound stops that was using a real hardware/software - # channel, it will start playing from where it should be. This technique - # saves CPU time (thousands of sounds can be played at once without actually - # being mixed or taking up resources), and also removes the need for the - # user to manage voices themselves. An example of virtual channel usage is a - # dungeon with 100 torches burning, all with a looping crackling sound, but - # with a sound-card that only supports 32 hardware voices. If the 3D - # positions and priorities for each torch are set correctly, FMOD will play - # all 100 sounds without any 'out of channels' errors, and swap the real - # voices in and out according to which torches are closest in 3D space. - # Priority for virtual channels can be changed in the sound's defaults, or - # at runtime with {Channel.priority}. - # - # @param sound [Sound] The sound to play. - # @param group [ChannelGroup] The {ChannelGroup} become a member of. This is - # more efficient than using {Channel.group}, as it does it during the - # channel setup, rather than connecting to the master channel group, then - # later disconnecting and connecting to the new {ChannelGroup} when - # specified. Specify +nil+ to ignore (use master {ChannelGroup}). - # @param paused [Boolean] flag to specify whether to start the channel - # paused or not. Starting a channel paused allows the user to alter its - # attributes without it being audible, and un-pausing with - # ChannelControl.resume actually starts the sound. - # - # @return [Channel] the newly playing channel. - def play_sound(sound, group = nil, paused = false) - FMOD.type?(sound, Sound) - channel = int_ptr - FMOD.invoke(:System_PlaySound, self, sound, group, paused.to_i, channel) - Channel.new(channel) - end - - def play_dsp(dsp, group = nil, paused = false) - FMOD.type?(dsp, Dsp) - channel = int_ptr - FMOD.invoke(:System_PlayDSP, self, dsp, group, paused.to_i, channel) - Channel.new(channel) - end - - def [](index) - reverb = Reverb.new - FMOD.invoke(:System_GetReverbProperties, self, index, reverb) - reverb - end - - def []=(index, reverb) - FMOD.type?(reverb, Reverb) - FMOD.invoke(:System_SetReverbProperties, self, index, reverb) - end - - def mixer_suspend - FMOD.invoke(:System_MixerSuspend, self) - if block_given? - yield - FMOD.invoke(:System_MixerResume, self) - end - end - - def mixer_resume - FMOD.invoke(:System_MixerResume, self) - end - - ## # Route the signal from a channel group into a separate audio port on the # output driver. # # Note that an FMOD port is a hardware specific reference, to hardware # devices that exist on only certain platforms (like a console headset, or @@ -1211,10 +1134,219 @@ def software_format=(format) FMOD.type?(format, SoftwareFormat) FMOD.invoke(:System_GetSoftwareFormat, self, *format.values) end + ## + # Retrieves the internal master channel group. This is the default channel + # group that all channels play on. + # + # This channel group can be used to do things like set the master volume for + # all playing sounds. See the ChannelGroup API for more functionality. + # @return [ChannelGroup] the internal master channel group. + def master_channel_group + FMOD.invoke(:System_GetMasterChannelGroup, self, group = int_ptr) + ChannelGroup.new(group) + end + + ## + # @@return [SoundGroup] the default sound group, where all sounds are placed + # when they are created. + def master_sound_group + FMOD.invoke(:System_GetMasterSoundGroup, self, group = int_ptr) + SoundGroup.new(group) + end + + ## + # Closes the {System} object without freeing the object's memory, so the + # system handle will still be valid. + # + # Closing the output renders objects created with this system object + # invalid. Make sure any sounds, channel groups, geometry and DSP objects + # are released before closing the system object. + # + # @return [void] + def close + FMOD.invoke(:System_Close, self) + end + + ## + # @!attribute [r] version + # @return [String] the current version of FMOD being used. + def version + FMOD.invoke(:System_GetVersion, self, version = "\0" * SIZEOF_INT) + FMOD.uint2version(version) + end + + ## + # Plays a sound object on a particular channel and {ChannelGroup}. + # + # When a sound is played, it will use the sound's default frequency and + # priority. + # + # A sound defined as {Mode::THREE_D} will by default play at the position of + # the listener. + # + # Channels are reference counted. If a channel is stolen by the FMOD + # priority system, then the handle to the stolen voice becomes invalid, and + # Channel based commands will not affect the new sound playing in its place. + # If all channels are currently full playing a sound, FMOD will steal a + # channel with the lowest priority sound. If more channels are playing than + # are currently available on the sound-card/sound device or software mixer, + # then FMOD will "virtualize" the channel. This type of channel is not + # heard, but it is updated as if it was playing. When its priority becomes + # high enough or another sound stops that was using a real hardware/software + # channel, it will start playing from where it should be. This technique + # saves CPU time (thousands of sounds can be played at once without actually + # being mixed or taking up resources), and also removes the need for the + # user to manage voices themselves. An example of virtual channel usage is a + # dungeon with 100 torches burning, all with a looping crackling sound, but + # with a sound-card that only supports 32 hardware voices. If the 3D + # positions and priorities for each torch are set correctly, FMOD will play + # all 100 sounds without any 'out of channels' errors, and swap the real + # voices in and out according to which torches are closest in 3D space. + # Priority for virtual channels can be changed in the sound's defaults, or + # at runtime with {Channel.priority}. + # + # @param sound [Sound] The sound to play. + # @param group [ChannelGroup] The {ChannelGroup} become a member of. This is + # more efficient than using {Channel.group}, as it does it during the + # channel setup, rather than connecting to the master channel group, then + # later disconnecting and connecting to the new {ChannelGroup} when + # specified. Specify +nil+ to ignore (use master {ChannelGroup}). + # @param paused [Boolean] flag to specify whether to start the channel + # paused or not. Starting a channel paused allows the user to alter its + # attributes without it being audible, and un-pausing with + # ChannelControl.resume actually starts the sound. + # + # @return [Channel] the newly playing channel. + def play_sound(sound, group = nil, paused = false) + FMOD.type?(sound, Sound) + channel = int_ptr + FMOD.invoke(:System_PlaySound, self, sound, group, paused.to_i, channel) + Channel.new(channel) + end + + ## + # Plays a sound object on a particular channel and {ChannelGroup}. + # + # When a sound is played, it will use the sound's default frequency and + # priority. + # + # A sound defined as {Mode::THREE_D} will by default play at the position of + # the listener. + # + # Channels are reference counted. If a channel is stolen by the FMOD + # priority system, then the handle to the stolen voice becomes invalid, and + # Channel based commands will not affect the new sound playing in its place. + # If all channels are currently full playing a sound, FMOD will steal a + # channel with the lowest priority sound. If more channels are playing than + # are currently available on the sound-card/sound device or software mixer, + # then FMOD will "virtualize" the channel. This type of channel is not + # heard, but it is updated as if it was playing. When its priority becomes + # high enough or another sound stops that was using a real hardware/software + # channel, it will start playing from where it should be. This technique + # saves CPU time (thousands of sounds can be played at once without actually + # being mixed or taking up resources), and also removes the need for the + # user to manage voices themselves. An example of virtual channel usage is a + # dungeon with 100 torches burning, all with a looping crackling sound, but + # with a sound-card that only supports 32 hardware voices. If the 3D + # positions and priorities for each torch are set correctly, FMOD will play + # all 100 sounds without any 'out of channels' errors, and swap the real + # voices in and out according to which torches are closest in 3D space. + # Priority for virtual channels can be changed in the sound's defaults, or + # at runtime with {Channel.priority}. + # + # @param dsp [Dsp] The DSP to play. + # @param group [ChannelGroup] The {ChannelGroup} become a member of. This is + # more efficient than using {Channel.group}, as it does it during the + # channel setup, rather than connecting to the master channel group, then + # later disconnecting and connecting to the new {ChannelGroup} when + # specified. Specify +nil+ to ignore (use master {ChannelGroup}). + # @param paused [Boolean] flag to specify whether to start the channel + # paused or not. Starting a channel paused allows the user to alter its + # attributes without it being audible, and un-pausing with + # ChannelControl.resume actually starts the sound. + # + # @return [Channel] the newly playing channel. + def play_dsp(dsp, group = nil, paused = false) + FMOD.type?(dsp, Dsp) + channel = int_ptr + FMOD.invoke(:System_PlayDSP, self, dsp, group, paused.to_i, channel) + Channel.new(channel) + end + + ## + # Suspend mixer thread and relinquish usage of audio hardware while + # maintaining internal state. + # + # @overload mixer_suspend + # When called with a block, automatically resumes the mixer when the block + # exits. + # @yield Yields control back to receiver. + # @overload mixer_suspend + # When called without a block, user must call {#mixer_resume}. + # + # @return [void] + # @see mixer_resume + def mixer_suspend + FMOD.invoke(:System_MixerSuspend, self) + if block_given? + yield + FMOD.invoke(:System_MixerResume, self) + end + end + + ## + # Resume mixer thread and reacquire access to audio hardware. + # @return [void] + # @see mixer_suspend + def mixer_resume + FMOD.invoke(:System_MixerResume, self) + end + + ## + # Retrieves the current reverb environment for the specified reverb + # instance. + # + # @param index [Integer] Index of the particular reverb instance to target, + # from 0 to {FMOD::MAX_REVERB} inclusive. + # + # @return [Reverb] The specified Reverb instance. + def [](index) + reverb = Reverb.new + FMOD.invoke(:System_GetReverbProperties, self, index, reverb) + reverb + end + + ## + # Sets parameters for the global reverb environment. + # + # @param index [Integer] Index of the particular reverb instance to target, + # from 0 to {FMOD::MAX_REVERB} inclusive. + # @param reverb [Reverb] A structure which defines the attributes for the + # reverb. Passing {FMOD::NULL} or +nil+ to this function will delete the + # physical reverb. + # + # @return [Reverb] the specified reverb. + def []=(index, reverb) + FMOD.type?(reverb, Reverb) + FMOD.invoke(:System_SetReverbProperties, self, index, reverb) + end + + alias_method :get_reverb, :[] + alias_method :set_reverb, :[]= + + ## + # @!attribute software_channels + # @return [Integer] the maximum number of software mixed channels possible. + integer_reader(:software_channels, :System_GetSoftwareChannels) + integer_writer(:software_channels=, :System_SetSoftwareChannels, 0, 64) + + ## + # @!attribute stream_buffer + # @return [StreamBuffer] the internal buffer-size for streams. def stream_buffer size, type = "\0" * SIZEOF_INT, "\0" * SIZEOF_INT FMOD.invoke(:System_GetStreamBufferSize, self, size, type) StreamBuffer.new(size.unpack1('L'), type.unpack1('l')) end @@ -1223,19 +1355,34 @@ FMOD.type?(buffer, StreamBuffer) raise RangeError, "size must be greater than 0" unless buffer.size > 0 FMOD.invoke(:System_SetStreamBufferSize, self, *buffer.values) end + ## + # @!attribute stream_buffer + # @return [DspBuffer] the internal buffer-size for DSP units. def dsp_buffer size, count = "\0" * SIZEOF_INT, "\0" * SIZEOF_INT FMOD.invoke(:System_GetDSPBufferSize, self, size, count) DspBuffer.new(size.unpack1('L'), count.unpack1('l')) end def dsp_buffer=(buffer) FMOD.type?(buffer, DspBuffer) raise RangeError, "size must be greater than 0" unless buffer.size > 0 FMOD.invoke(:System_SetDSPBufferSize, self, *buffer.values) + end + + ## + # Updates the FMOD system. This should be called once per "game tick", or + # once per frame in your application. + # + # @note Various callbacks are driven from this function, and it must be + # called for them to be invoked. + # + # @return [void] + def update + FMOD.invoke(:System_Update, self) end end end