indexing description: "[ Implements a simple sound player. This player can play either WAVE, AIFF, RIFF, OGG or VOC. Use this player if you don't want to handle all sound stuff by your own. This player let's you play sound files in a very very easy way. This class was designed for having sound support in a hurry. We recommend to use it whenever you need just to play sound. Note: This is typically used to play sound effects, whereas EM_MUSIC_PLAYER is used to play music. ]" date: "$Date$" revision: "$Revision$" class EM_SOUND_PLAYER inherit EM_SHARED_SUBSYSTEMS export {NONE} all end EM_SHARED_AUDIO_FACTORY export {NONE} all end EM_SHARED_AUDIO_EVENTS export {NONE} all end EM_AUDIO_CONSTANTS export {NONE} all end EM_TIME_SINGLETON export {NONE} all end EM_CONSTANTS export {NONE} all end EM_FUNCTIONS_EXTERNAL export {NONE} all end SDL_FUNCTIONS_EXTERNAL export {NONE} all end SDL_MIXER_FUNCTIONS_EXTERNAL export {NONE} all end create make_with_path,make_with_list,make_with_file,make_empty feature {NONE} -- Initialization initialize_subsystem is -- Initialize audio subsystem. do audio_subsystem.enable if audio_subsystem.is_enabled then audio_subsystem.mixer.open_default did_initialize_subsystem := True end end make_with_path (a_path: STRING; an_extension_list: DS_LINKED_LIST [STRING]; do_recursive_search: BOOLEAN; do_initialize_subsystem: BOOLEAN) is -- Make playlist from `a_path' searching for file with -- extensions in `an_extension_list'. -- -- If you want to search files also in subfolders, set -- `do_recursive_search' to True. -- -- This player may initialize the audio subsystem for you. -- Use `do_initialize_subsystem' to have it enabled by this player. require a_path_not_void: a_path /= Void do make_empty (do_initialize_subsystem) create playlist.make_with_path (a_path, an_extension_list, do_recursive_search) end make_with_list (a_list: DS_LINKED_LIST [STRING]; do_initialize_subsystem: BOOLEAN) is -- Make playlist from `a_list'. -- -- This player may initialize the audio subsystem for you. -- Use `do_initialize_subsystem' to have it enabled by this player. do make_empty (do_initialize_subsystem) create playlist.make_with_list (a_list) end make_with_file (a_filename: STRING; do_initialize_subsystem: BOOLEAN) is -- Make playlist with `a_filename'. -- -- This player may initialize the audio subsystem for you. -- Use `do_initialize_subsystem' to have it enabled by this player. require a_filename_not_void: a_filename /= Void do make_empty (do_initialize_subsystem) playlist.extend (a_filename) ensure playlist_count_is_valid: playlist.count = 1 end make_empty (do_initialize_subsystem: BOOLEAN) is -- Make with an empty playlist -- -- This player may initialize the audio subsystem for you. -- Use `do_initialize_subsystem' to have it enabled by this player. do if do_initialize_subsystem then initialize_subsystem end audio_events.channel_finished_event.subscribe (agent channel_finished) volume := Em_max_volume create playlist.make_empty create playing_channels.make create preloaded_sounds.make (7) ensure playlist_count_is_valid: playlist.count = 0 end feature -- Playback preload_sounds is -- preload all sound files local i: INTEGER do preloaded_sounds.wipe_out from i := 1 until i > playlist.count loop audio_factory.create_sound_from_file (playlist.get_i_th (i)) preloaded_sounds.force (audio_factory.last_sound, i) i := i + 1 end end play_file (a_filename: STRING; a_loop_count: INTEGER) is -- Play file at location `a_filename' for `a_loop_count' times. do if playlist.has (a_filename) then play_i_th (playlist.position (a_filename), a_loop_count) else playlist.extend (a_filename) play_i_th (playlist.count, a_loop_count) end end stop_file (a_filename: STRING) is -- Stop playing file at location `a_filename'. do if playlist.has (a_filename) then stop_i_th (playlist.position (a_filename)) end end play_i_th (an_index: INTEGER; a_loop_count: INTEGER) is -- Play item at position `an_index' in playlist for `a_loop_count' times. require valid_index: an_index >= 1 and then an_index <= playlist.count local a_filename: STRING sound: EM_SOUND do if preloaded_sounds.has (an_index) then sound := preloaded_sounds.item (an_index) else a_filename := playlist.get_i_th (an_index) audio_factory.create_sound_from_file (a_filename) sound := audio_factory.last_sound end sound.set_volume (volume) if not audio_subsystem.mixer.channels.has_available_channel then audio_subsystem.mixer.channels.extend (1) end playing_channels.put_last ([an_index, audio_subsystem.mixer.channels.first_available_channel]) audio_subsystem.mixer.channels.first_available_channel.play (sound, a_loop_count) end stop_i_th (an_index: INTEGER) is -- Stop playing file at position `an_index'. require valid_index: an_index >= 1 and then an_index <= playlist.count local chan: EM_CHANNEL do chan := find_channel_with_sound (an_index) if chan /= Void then if chan.is_playing then chan.stop remove_channel_with_sound (an_index) end end end stop_all is -- Stop all playing sound files. local i: INTEGER chan: EM_CHANNEL do from i := 1 until i > playing_channels.count loop chan ?= playing_channels.item (i).item (2) if chan.is_playing then chan.stop end i := i + 1 end create playing_channels.make end feature {NONE} -- Playback support channel_finished (a_channel: INTEGER) is -- Event is fired whan `a_channel' finishes playback. local i: INTEGER chan: EM_CHANNEL break: BOOLEAN do debug ("em_audio") io.put_string ("channel ") io.put_integer (a_channel) io.put_string (" has finished playing") io.put_new_line end from break := False i := 1 until break or else i > playing_channels.count loop chan ?= playing_channels.item (i).item (2) if chan /= Void then if chan.number = a_channel then playing_channels.remove (i) break := True end end i := i + 1 end end find_channel_with_sound (an_index: INTEGER): EM_CHANNEL is -- Find channel where soundfile at `an_index' is playing. local i: INTEGER k: INTEGER_REF break: BOOLEAN do from Result := Void break := False i := 1 until break or else i > playing_channels.count loop k ?= playing_channels.item (i).item (1) if k.to_integer = an_index then Result ?= playing_channels.item (i).item (2) break := True end i := i + 1 end end remove_channel_with_sound (an_index: INTEGER) is -- Remove channel where soundfile at `an_index' is playing. local i: INTEGER k: INTEGER_REF break: BOOLEAN do from break := False i := 1 until break or else i > playing_channels.count loop k ?= playing_channels.item (i).item (1) if k.to_integer = an_index then playing_channels.remove (i) break := True end i := i + 1 end end feature -- Access volume: INTEGER -- Volume of player playlist: EM_PLAYLIST -- Playlist of the player. did_initialize_subsystem: BOOLEAN -- Has the subsystem been initialized by the player? is_i_th_playing (an_index: INTEGER): BOOLEAN is -- Is file with `an_index' playing? local chan: EM_CHANNEL do Result := False chan := find_channel_with_sound (an_index) if chan /= Void then Result := chan.is_playing end end feature -- Setters set_volume (a_volume: like volume) is -- Set `volume' to `a_volume'. do volume := a_volume ensure volume_assigned: volume = a_volume end feature {NONE} -- Internal variables playing_channels: DS_LINKED_LIST [TUPLE [INTEGER, EM_CHANNEL]] -- Stores playing channels and index of file played. preloaded_sounds: DS_HASH_TABLE [EM_SOUND, INTEGER] -- Stores preloaded sounds for faster playing invariant playlist_created: playlist /= Void playing_channels_created: playing_channels /= Void end