indexing description: "[ Implements current music channel part in the mixer. Use this class to create the music channel. Note: You need to give the master for creating the music channel, because the music channel needs to access it. In the music channel you can play music from the playlist. ]" date: "$Date$" revision: "$Revision$" class MIXER_MUSIC_CHANNEL inherit MIXER_CONSTANTS export {NONE} all end EM_AUDIO_CONSTANTS export {NONE} all end EM_PANEL EM_SHARED_AUDIO_FACTORY export {NONE} all end EM_SHARED_AUDIO_EVENTS export {NONE} all end create make feature {NONE} -- Initialization make (a_master: like master) is -- Initialize music channel require a_master_not_void: a_master /= Void do make_void_surface master := a_master make_playlist make_playback make_volume create active.make_with_image_positioned ("active.png", 42, 285) active.clicked_event.subscribe (agent active_button_clicked) add_widget (active) stop_pressed := False create callback_receiver.make callback_receiver.music_finished.subscribe (agent music_finished) audio_events.music_finished_event.subscribe (agent music_finished) end make_playlist is -- Create playlist from music_directory local extension_list: DS_LINKED_LIST [STRING] i: INTEGER filename: STRING playlist: EM_PLAYLIST do create extension_list.make extension_list.put_last (".mp3") extension_list.put_last (".ogg") extension_list.put_last (".wav") extension_list.put_last (".mid") extension_list.put_last (".mod") create playlist.make_with_path (music_directory, extension_list, True) create listbox.make_empty from i := 1 until i > playlist.count loop filename := playlist.get_i_th (i) listbox.put (filename.substring (music_directory.count + 2, filename.count)) i := i + 1 end listbox.set_position (45, 35) listbox.set_dimension (174, 205) listbox.set_transparent listbox.set_border (create {EM_NO_BORDER}) listbox.set_font (create {EM_TTF_FONT}.make_from_ttf_file ("slicker.ttf", 10)) listbox.set_selection_background_color (create {EM_COLOR}.make_with_rgb (102, 102, 102)) add_widget (listbox) end make_playback is -- Create the playback area in the channels. do -- Create play button create play.make_with_image_positioned (Void, 42, 350) play.clicked_event.subscribe (agent play_button_clicked) add_widget (play) -- Create stop button create stop.make_with_image_positioned (Void, 81, 350) stop.clicked_event.subscribe (agent stop_button_clicked) add_widget (stop) -- Create back button create back.make_with_image_positioned (Void, 42, 377) back.clicked_event.subscribe (agent back_button_clicked) add_widget (back) -- Create forth button create forth.make_with_image_positioned (Void, 81, 377) forth.clicked_event.subscribe (agent forth_button_clicked) add_widget (forth) -- Create mute button create mute.make_with_image_positioned ("mute.png", 42, 404) mute.clicked_event.subscribe (agent mute_button_clicked) add_widget (mute) -- Create repeat button create repeat.make_with_image_positioned ("reverse.png", 81, 404) repeat.clicked_event.subscribe (agent repeat_button_clicked) add_widget (repeat) -- Create fade button create fade.make_with_image_positioned ("fade.png", 42, 431) fade.clicked_event.subscribe (agent fade_button_clicked) add_widget (fade) -- Create fade value textbox create fade_value.make_with_text_positioned ("", 83, 431) fade_value.key_down_event.subscribe (agent fade_value_changed) add_widget (fade_value) create old_fade_value.make_from_string (fade_value.text) end make_volume is -- Create the volume slider for the music channel. do create volume.make_positioned (150, 285) volume.position_changed_event.subscribe (agent volume_changed) volume.disable add_widget (volume) end feature -- Access active: MIXER_BUTTON_LARGE -- Active button play: MIXER_BUTTON_MEDIUM -- Play button stop: MIXER_BUTTON_MEDIUM -- Stop button forth: MIXER_BUTTON_MEDIUM -- Forth button back: MIXER_BUTTON_MEDIUM -- Back button mute: MIXER_BUTTON_MEDIUM -- Mute button repeat: MIXER_BUTTON_MEDIUM -- Repeat button fade: MIXER_BUTTON_MEDIUM -- Fade button fade_value: MIXER_TEXTBOX -- Fade value textbox volume: MIXER_SLIDER_VOLUME -- Volume slider listbox: EM_TEXTLIST [STRING] -- Listbox with songs master: MIXER_MASTER -- Access to Master of Mixer track: EM_MUSIC -- Current music track feature -- Events active_button_clicked is -- Event for the active button. -- With a non-active music channel you can't change anything. do active.toggle_active if active.active then playing_id := -1 fade_value.set_text ("1000") volume.enable else if track /= Void and then track.is_playing then stop_pressed := True if fade.active then track.fade_out (fade_value.text.to_integer) from until not track.is_fading_out loop end else track.stop end end volume.set_current_value (volume.right_value) if mute.active then mute.toggle_active end if repeat.active then repeat.toggle_active end if fade.active then fade.toggle_active end fade_value.set_text ("") volume.disable end create old_fade_value.make_from_string (fade_value.text) ensure active_is_changed: active.active = not old active.active end play_button_clicked is -- Event for the play button. -- Plays a new music file or pause/resume it. local error_occured: BOOLEAN do if not error_occured then if master.active.active and then active.active then if track /= Void and then track.is_playing and then not track.is_paused and then playing_id = listbox.selected_index then track.pause else if playing_id = listbox.selected_index then track.resume else if listbox.selected_index = 0 then listbox.set_selected_index (1) end audio_factory.create_music_from_file (music_directory + "/" + listbox.selected_element) track := audio_factory.last_music track.set_volume ((volume.current_volume * (master.volume.current_volume / Em_max_volume)).rounded) if fade.active then listbox.redraw track.fade_in (1, fade_value.text.to_integer) from until not track.is_fading_in loop end else track.play (1) end playing_id := listbox.selected_index end end end end rescue error_occured := true retry end stop_button_clicked is -- Event for stop button. -- Stops active playing music channel. do if active.active then if track /= Void and then track.is_playing then stop_pressed := True if fade.active then track.fade_out (fade_value.text.to_integer) from until not track.is_fading_out loop end else track.stop end end playing_id := -1 end end forth_button_clicked is -- Event for forth button. -- Jumps to next file in playlist. local error_occured: BOOLEAN do if not error_occured then if active.active then if listbox.selected_index = listbox.count then if repeat.active then if track /= Void and then track.is_playing then stop_pressed := True if fade.active then track.fade_out (fade_value.text.to_integer) from until not track.is_fading_out loop end else track.stop end listbox.set_selected_index (1) audio_factory.create_music_from_file (music_directory + "/" + listbox.selected_element) track := audio_factory.last_music if master.active.active then if fade.active then listbox.redraw track.fade_in (1, fade_value.text.to_integer) from until not track.is_fading_in loop end else track.play (1) end end end end else if track /= Void and then track.is_playing then stop_pressed := True if fade.active then track.fade_out (fade_value.text.to_integer) from until not track.is_fading_out loop end else track.stop end listbox.set_selected_index (listbox.selected_index + 1) audio_factory.create_music_from_file (music_directory + "/" + listbox.selected_element) track := audio_factory.last_music if master.active.active then if fade.active then listbox.redraw track.fade_in (1, fade_value.text.to_integer) from until not track.is_fading_in loop end else track.play (1) end end else listbox.set_selected_index (listbox.selected_index + 1) end end end end rescue error_occured := true retry end back_button_clicked is -- Event for back button. -- Jumps to previous file in playlist. local error_occured: BOOLEAN do if not error_occured then if active.active then if listbox.selected_index <= 1 then listbox.set_selected_index (listbox.count) if repeat.active then if track /= Void and then track.is_playing then stop_pressed := True if fade.active then track.fade_out (fade_value.text.to_integer) from until not track.is_fading_out loop end else track.stop end audio_factory.create_music_from_file (music_directory + "/" + listbox.selected_element) track := audio_factory.last_music if master.active.active then if fade.active then listbox.redraw track.fade_in (1, fade_value.text.to_integer) from until not track.is_fading_in loop end else track.play (1) end end end end else if track /= Void and then track.is_playing then stop_pressed := True if fade.active then track.fade_out (fade_value.text.to_integer) from until not track.is_fading_out loop end else track.stop end listbox.set_selected_index (listbox.selected_index - 1) audio_factory.create_music_from_file (music_directory + "/" + listbox.selected_element) track := audio_factory.last_music if master.active.active then if fade.active then listbox.redraw track.fade_in (1, fade_value.text.to_integer) from until not track.is_fading_in loop end else track.play (1) end end else listbox.set_selected_index (listbox.selected_index - 1) end end end end rescue error_occured := true retry end mute_button_clicked is -- Event for mute button. -- Mute or unmute the music channel. do if active.active then mute.toggle_active if track /= Void then if mute.active then track.set_volume (0) else if master.active.active and then not master.mute.active then track.set_volume ((volume.current_volume * (master.volume.current_volume / Em_max_volume)).rounded) end end end end end repeat_button_clicked is -- Event for repeat button. -- If active the music file will be repeated. do if active.active then repeat.toggle_active end end fade_button_clicked is -- Event for fade button. -- If fade is activatet, the fade effect is used in play and stop with current fade_value. do if active.active then fade.toggle_active end end feature -- Events music_finished is -- Event when the music played is finish. local error_occured: BOOLEAN do if not error_occured then if not stop_pressed then if listbox.selected_index = listbox.count then if repeat.active then listbox.set_selected_index (1) audio_factory.create_music_from_file (music_directory + "/" + listbox.selected_element) track := audio_factory.last_music if not mute.active and then not master.mute.active then if fade.active then listbox.redraw track.fade_in (1, fade_value.text.to_integer) from until not track.is_fading_in loop end else track.play (1) end end end else listbox.set_selected_index (listbox.selected_index + 1) audio_factory.create_music_from_file (music_directory + "/" + listbox.selected_element) track := audio_factory.last_music if not mute.active and then not master.mute.active then if fade.active then listbox.redraw track.fade_in (1, fade_value.text.to_integer) from until not track.is_fading_in loop end else track.play (1) end end end end stop_pressed := False end rescue error_occured := true retry end fade_value_changed (a_keyboard_event: EM_KEYBOARD_EVENT) is -- Event for fade value changed. -- Sets the value for the fade effect. do if active.active and then fade_value.text.is_integer then create old_fade_value.make_from_string (fade_value.text) elseif fade_value.text.is_empty then fade_value.set_text ("0") else fade_value.set_text (create {STRING}.make_from_string (old_fade_value)) end end volume_changed (a_volume: INTEGER) is -- Event if volume's changed. -- Updates the volume slider and the volume value. -- `a_volume': is the current volume value given by the subscribe event. do volume.update_lights if active.active then if track /= Void then if master.active.active and then not mute.active and then not master.mute.active then track.set_volume ((volume.current_volume * (master.volume.current_volume / Em_max_volume)).rounded) end end end end feature {MIXER_MUSIC_CHANNEL, MIXER_MASTER} -- Setters set_track (a_track: like track) is -- Set the channel track. do track := a_track end set_playing_id (an_id: like playing_id) is -- Set the playing id. do playing_id := an_id end set_stop_pressed (a_stop_pressed: like stop_pressed) is -- Set stop_pressed to `a_stop_pressed' do stop_pressed := a_stop_pressed end feature {MIXER_MUSIC_CHANNEL, MIXER_MASTER} -- Variable playing_id: INTEGER -- An id for the playing status feature {NONE} -- Internal variables old_fade_value: STRING -- Stores the old fade value callback_receiver: EM_MUSIC_FINISHED -- Object which receives callback when music finished playing stop_pressed: BOOLEAN -- Should music_finished be executed or not? end