indexing description: "[ Implements a channel container for use with audio mixer. Use this class to apply effects and other manipulations to all allocated channels. You should use this class to create new channels or remove some old ones. ]" date: "$Date$" revision: "$Revision$" class EM_CHANNELS inherit EM_AUDIO_CONSTANTS export {NONE} all {ANY} Em_max_volume end EM_SHARED_ERROR_HANDLER export {NONE} all end SDL_MIXER_FUNCTIONS_EXTERNAL export {NONE} all end create make_empty feature {NONE} -- Initialization make_empty is -- Create container for channels. local i: INTEGER do create channel_list.make create groups.make_empty create postmix_effects.make_empty i := mix_allocate_channels_external (0) end allocate (a_number_of_channels: INTEGER): INTEGER is -- Allocate `a_number_of_channels' for the mixer. -- -- Passing in negative values causes the mixer to deallocate some channels. -- -- Returns the number of alloctated channels. require number_valid: a_number_of_channels + count >= 0 local a_number: INTEGER do a_number := a_number_of_channels + count Result := mix_allocate_channels_external (a_number) if Result > channel_list.count then from until Result = channel_list.count loop channel_list.put_last (create {EM_CHANNEL}.make (Em_max_volume, channel_list.count + 1)) end else channel_list.keep_first (Result) end ensure allocated: Result = a_number_of_channels + old count end feature -- Setters set_volume (a_volume: like volume) is -- Set volume for all channels. require volume_in_range: 0 <= a_volume and then a_volume <= Em_max_volume local i: INTEGER do i := mix_volume_external (-1, a_volume) ensure volume_set: volume = a_volume end mute_all is -- Mute all channels. do from channel_list.start until channel_list.after loop if not channel_list.item_for_iteration.is_mute then channel_list.item_for_iteration.toggle_mute end channel_list.forth end end unmute_all is -- Unmute all channels. do from channel_list.start until channel_list.after loop if channel_list.item_for_iteration.is_mute then channel_list.item_for_iteration.toggle_mute end channel_list.forth end end toggle_reverse_stereo_all is -- Reverse stereo for all channels. do from channel_list.start until channel_list.after loop channel_list.item_for_iteration.toggle_reverse_stereo channel_list.forth end end feature -- Effects register_effect_to_all (an_effect: EM_EFFECT; an_argument: POINTER): INTEGER is -- Register `an_effect' with `an_argument' for all channels. -- -- `an_effect' will be added to each channel's effect-list. -- -- Use `an_argument' if the effect needs some user parameters. require effect_not_void: an_effect /= Void do from channel_list.start until channel_list.after loop channel_list.item_for_iteration.register_effect (an_effect, an_argument) channel_list.forth end end unregister_all_effects is -- Removes all effects from any channel. do from channel_list.start until channel_list.after loop channel_list.item_for_iteration.unregister_all_effects channel_list.forth end end feature -- Postmixing register_postmix_effect (an_effect: EM_EFFECT; an_argument: POINTER) is -- Register `an_effect' with `an_argument' for the postmix channel. -- -- The effect will be added to the postmix effects-list. -- -- Use `an_argument' if the effect needs some user parameters. require effect_not_void: an_effect /= Void local i: INTEGER fx_func: MIX_EFFECT_FUNC_T_DISPATCHER fx_done: MIX_EFFECT_DONE_T_DISPATCHER do create fx_func.make (an_effect) create fx_done.make (an_effect) an_effect.set_effect_function (fx_func.c_dispatcher) an_effect.set_effect_done (fx_done.c_dispatcher) i := mix_register_effect_external (Em_channel_postmix, an_effect.effect_function, an_effect.effect_done, an_argument) postmix_effects.extend (an_effect) ensure effect_added: postmix_effects.count = old postmix_effects.count + 1 end unregister_postmix_effect (an_effect: EM_EFFECT) is -- Remove all effects corresponding to `an_effect' from the postmix effects. require effect_not_void: an_effect /= Void local i: INTEGER do i := mix_unregister_effect_external (Em_channel_postmix, an_effect.effect_function) if i = 0 then error_handler.raise_error (error_handler.Em_error_unregistring_effect, []) end postmix_effects.remove (an_effect) ensure effect_removed: postmix_effects.count < old postmix_effects.count end unregister_all_postmix_effects is -- This removes all registered postmix effects. local i: INTEGER do i := mix_unregister_all_effects_external (Em_channel_postmix) end feature -- Access volume: INTEGER is -- Average volume of all channels do Result := mix_volume_external (-1, -1) end count: INTEGER is -- Number of channels do Result := channel_list.count end playing_count: INTEGER is -- Number of playing channels -- -- Attention: Also paused channels are playing. do Result := mix_playing_external (-1) end pausing_count: INTEGER is -- Number of paused channels -- -- Attention: If a channel was halted after pausing -- channel will still be in paused mode. do Result := mix_paused_external (-1) end allocated_count: INTEGER is -- Number of allocated channels -- -- Note: This value must not be the same as count. do Result := mix_allocate_channels_external (-1) end i_th (i: INTEGER): EM_CHANNEL is -- I'th channel require valid_index: 1 <= i and then i <= count do Result := channel_list.item (i) ensure Result_set: channel_list.item (i) = Result end groups: EM_AUDIO_GROUPS -- Channel groups postmix_effects: EM_EFFECTS -- Postmix effects has_available_channel: BOOLEAN is -- Is there an available channel? do Result := mix_group_available_external (-1) /= -1 end first_available_channel: EM_CHANNEL is -- First available channel local i: INTEGER do i := mix_group_available_external (-1) Result := channel_list.item (i + 1) end oldest_busy_channel: EM_CHANNEL is -- Oldest available channel local i: INTEGER do i := mix_group_oldest_external (-1) Result := channel_list.item (i + 1) end newest_busy_channel: EM_CHANNEL is -- Newest available channel local i: INTEGER do i := mix_group_newer_external (-1) Result := channel_list.item (i + 1) end feature -- Operations extend (a_number: INTEGER) is -- Extend `a_number' of channels. require valid_number: a_number >= 0 local i: INTEGER do i := allocate (a_number) end put (a_channel: EM_CHANNEL; an_index: INTEGER) is -- Put `a_channel' at position `an_index'. require valid_index: an_index >= 1 and then an_index <= count channel_not_void: a_channel /= Void valid_channel: a_channel.number = an_index do channel_list.put (a_channel, an_index) ensure channel_set: channel_list.item (an_index) = a_channel end remove (a_number: INTEGER) is -- Remove `a_number' of channels. require valid_number: a_number <= count local i: INTEGER do i := allocate (-a_number) end reserve (a_number: INTEGER): INTEGER is -- Reserve some channels for not being used in the default channel group. -- -- Returns amount of reserved channels. require valid_num: a_number >= 0 and a_number <= count do Result := mix_reserve_channels_external (a_number) ensure Result_positiv: Result >= 0 end feature -- Playback play_on_first_free_channel (a_sound: EM_SOUND; a_loop_count: INTEGER) is -- Play `a_sound' on first free channel for `a_loop_count' times. -- -- Passing in -1 for `a_loop_count' will loop infinite times. require sound_not_void: a_sound /= Void local i: INTEGER do i := mix_play_channel_timed_external (-1, a_sound.to_pointer, a_loop_count, -1) if i = -1 then error_handler.raise_error (error_handler.Em_error_playing_channel_timed, [a_loop_count]) end end play_timed_on_first_free_channel (a_sound: EM_SOUND; a_loop_count: INTEGER; a_tick_count: INTEGER) is -- Play `a_sound' on first free channel for `a_loop_count' times and a maximum -- of `a_tick_count' milliseconds. -- -- Passing in -1 for `a_loop_count' will loop infinite times. -- Passing in -1 for `a_tick_count' will play forever. require sound_not_void: a_sound /= Void local i: INTEGER do i := mix_play_channel_timed_external (-1, a_sound.to_pointer, a_loop_count, a_tick_count) if i = -1 then error_handler.raise_error (error_handler.Em_error_playing_channel_timed, [a_loop_count, a_tick_count]) end end fade_in_on_first_free_channel (a_sound: EM_SOUND; a_loop_count: INTEGER; a_duration: INTEGER) is -- Play `a_sound' on first free channel for `a_loop_count' times after -- a fade in of `a_duration' milliseconds. -- -- Passing in -1 for `a_loop_count' will loop infinite times. -- -- Attention: This function is non-blocking. -- Please check if the channel is fading before -- you quit your application. require sound_not_void: a_sound /= Void valid_duration: a_duration >= 0 local i: INTEGER do i := mix_fade_in_channel_timed_external (-1, a_sound.to_pointer, a_loop_count, a_duration, -1) if i = -1 then error_handler.raise_error (error_handler.Em_error_fading_channel_in_timed, [a_loop_count, a_duration]) end end fade_in_timed_on_first_free_channel (a_sound: EM_SOUND; a_loop_count: INTEGER; a_duration: INTEGER; a_tick_count: INTEGER) is -- Play `a_sound' on first free channel for `a_loop_count' times after -- a fade in of `a_duration' milliseconds for a maximum of `a_tick_count' -- milliseconds. -- -- Passing in -1 for `a_loop_count' will loop infinite times. -- Passing in -1 for `a_tick_count' will play forever. -- -- Attention: This function is non-blocking. -- Please check if the channel is fading before -- you quit your application. require sound_not_void: a_sound /= Void valid_duration: a_duration >= 0 local i: INTEGER do i := mix_fade_in_channel_timed_external (-1, a_sound.to_pointer, a_loop_count, a_duration, a_tick_count) if i = -1 then error_handler.raise_error (error_handler.Em_error_fading_channel_in_timed, [a_loop_count, a_duration, a_tick_count]) end end feature -- Pausing/Resuming pause_all is -- Pause all playing channels. do mix_pause_external (-1) end resume_all is -- Resume all paused channels. do mix_resume_external (-1) end feature -- Stopping stop_all is -- Stop playing all channels. local i: INTEGER do i := mix_halt_channel_external (-1) end expire_all (a_tick_count: INTEGER) is -- Stop playing channels after `a_tick_count' milliseconds. require valid_ticks: a_tick_count >= 0 local i: INTEGER do i := mix_expire_channel_external (-1, a_tick_count) end fade_out_all (a_duration: INTEGER) is -- Stop playing all channels after a fade out of `a_duration' milliseconds. -- -- Attention: This function is non-blocking. -- Please check if the channel is fading before -- you quit your application. require valid_duration: a_duration >= 0 local i: INTEGER do i := mix_fade_out_channel_external (-1, a_duration) end feature {NONE} -- Internal variables channel_list: DS_LINKED_LIST [EM_CHANNEL] -- All channels invariant channel_list_created: channel_list /= Void groups_created: groups /= Void postmix_effects_created: postmix_effects /= Void end