indexing description: "[ Class for wrapping C SDL_CD struct. This class represents a cdrom drive. ]" date: "$Date$" revision: "$Revision$" class EM_CDROM inherit EM_CONSTANTS export {NONE} all end EM_SHARED_SUBSYSTEMS export {NONE} all end EM_SHARED_ERROR_HANDLER export {NONE} all end SDL_CD_STRUCT_EXTERNAL export {NONE} all end SDL_CDROM_FUNCTIONS_EXTERNAL export {NONE} all end EWG_STRUCT create make_default, make_for_device feature {NONE} -- Implementation sizeof: INTEGER is do Result := sizeof_external end feature {NONE} -- Initialization make_default is -- Initialize default CD-Rom device `0' do make_for_device (0) end make_for_device (a_device: INTEGER) is -- Initialize CD-Rom device `a_device' require cdrom_subsystem_enbaled: cdrom_subsystem.is_enabled valid_device: a_device >= 0 and a_device < cdrom_subsystem.count do -- open the new device handler make_shared (sdl_cdopen_external (a_device)) -- set device indetifier and regiter it device := a_device cdrom_subsystem.register_device (current) -- Mark `current' as valid valid_handler := true ensure device_set: device = a_device device_registered: cdrom_subsystem.devices.has (current) end feature -- Device handler handling close is -- Here free the device handler -- Automatically called by the cdrom_subsystem if called `disable' require valid_cdrom_handler: exists implies valid_handler do -- stop playback if playing if is_playing or is_paused then stop end cdrom_subsystem.unregister_device (current) sdl_cdclose_external (item) -- Mark `current' as invalid valid_handler := false ensure device_unregistered: not cdrom_subsystem.devices.has (current) end feature -- CDRom Access name: STRING is -- return the cdrom device identifier -- this argument is system dependent local str: EWG_ZERO_TERMINATED_STRING do -- This has to be done shared: SDL collects everything create str.make_shared (sdl_cdname_external (device)) result := str.string end play_cd is -- play the entire cd require valid_cdrom_handler: exists implies valid_handler cd_in_drive: has_cd_in_drive local error_code: INTEGER do update_status error_code := sdl_cdplay_tracks_external (item, 0, 0, 0, 0) if error_code /= 0 then error_handler.set_error (error_handler.em_error_cdrom_play_track) end end play_cd_from_track (a_track: INTEGER) is -- play the entire cd beginning from track `a_track' require valid_cdrom_handler: exists implies valid_handler cd_in_drive: has_cd_in_drive valid_track: 0 < a_track and a_track < count local error_code: INTEGER do update_status error_code := sdl_cdplay_tracks_external (item, a_track, 0, 0, 0) if error_code /= 0 then error_handler.set_error (error_handler.em_error_cdrom_play_track) end end play_track (a_track: INTEGER) is -- play only track `a_track' require valid_cdrom_handler: exists implies valid_handler cd_in_drive: has_cd_in_drive valid_track: 0 < a_track and a_track < count local error_code: INTEGER do update_status error_code := sdl_cdplay_tracks_external (item, a_track, 0, 1, 0) if error_code /= 0 then error_handler.set_error (error_handler.em_error_cdrom_play_track) end end pause is -- pause playback require valid_cdrom_handler: exists implies valid_handler cd_in_drive: has_cd_in_drive not_paused: not is_paused local error_code: INTEGER do error_code := sdl_cdpause_external (item) if error_code /= 0 then error_handler.set_error (error_handler.em_error_cdrom_pause) end ensure cd_status_set: is_paused end resume is -- resume playback require valid_cdrom_handler: exists implies valid_handler cd_in_drive: has_cd_in_drive is_paused: is_paused local error_code: INTEGER do error_code := sdl_cdresume_external (item) if error_code /= 0 then error_handler.set_error (error_handler.em_error_cdrom_resume) end ensure cd_status_set: not is_paused end stop is -- stop playback require valid_cdrom_handler: exists implies valid_handler cd_in_drive: has_cd_in_drive local error_code: INTEGER do error_code := sdl_cdstop_external (item) if error_code /= 0 then error_handler.set_error (error_handler.em_error_cdrom_stop) end ensure cd_status_set: is_stopped end next is -- go to next track an play it -- if last track reached, replay require valid_cdrom_handler: exists implies valid_handler cd_in_drive: has_cd_in_drive is_playing: is_playing local cur_track: INTEGER do cur_track := current_track if cur_track = count then play_cd_from_track (cur_track) else play_cd_from_track (cur_track +1) end ensure correct_track: (current_track = old current_track +1) or current_track = count end previous is -- go to previous track and play it -- if first track reached, replay require valid_cdrom_handler: exists implies valid_handler cd_in_drive: has_cd_in_drive is_playing: is_playing local cur_track: INTEGER do cur_track := current_track if cur_track = 1 then play_cd_from_track (0) else play_cd_from_track (cur_track -1) end ensure correct_track: (current_track = old current_track -1) or current_track = 1 end eject is -- eject the given cdrom even if it has no cd in drive -- Be warned: this procedure does not work on every hardware require valid_cdrom_handler: exists implies valid_handler local error_code: INTEGER do error_code := sdl_cdeject_external (item) if error_code /= 0 then error_handler.set_error (error_handler.em_error_cdrom_eject) end end feature -- Properties device: INTEGER -- Device indentifier -- `0' is the default device device_id: INTEGER is -- returns the private drive identifier require valid_cdrom_handler: exists implies valid_handler do update_status result := get_id_external (item) ensure device_id_correct: result = get_id_external (item) end current_track: INTEGER is -- give the current played track, if any require valid_cdrom_handler: exists implies valid_handler do update_status result := get_cur_track_external (item) ensure current_track_correct: result = get_cur_track_external (item) end current_track_length: INTEGER is -- gives the length of the current track local all_tracks: DS_LINKED_LIST [EM_CDROM_TRACK] do if is_playing then all_tracks := tracks result := all_tracks.item (1 + current_track).length end end current_track_length_string: STRING is -- return an human readable length string (hh:mm:ss) local len: INTEGER hours, minutes, seconds: INTEGER do create result.make_empty len := current_track_length seconds := len \\ 60 minutes := (len // 60) \\ 60 hours := (len // 3600) -- format the time in a human readable form (hh:mm:ss) if hours < 10 then result := "0" end result := result + hours.out + ":" if minutes < 10 then result := result + "0" end result := result + minutes.out + ":" if seconds < 10 then result := result + "0" end result := result + seconds.out end current_time: INTEGER is -- gives the current playback time, from the beginning require valid_cdrom_handler: exists implies valid_handler do update_status result := get_cur_frame_external (item) // Em_cdrom_fps ensure current_time_correct: result = get_cur_frame_external (item) // Em_cdrom_fps end current_time_string: STRING is -- return an human readable time string (hh:mm:ss) require valid_cdrom_handler: exists implies valid_handler local len: INTEGER hours, minutes, seconds: INTEGER do create result.make_empty len := current_time seconds := len \\ 60 minutes := (len // 60) \\ 60 hours := (len // 3600) \\ 60 -- format the time in a human readable form (hh:mm:ss) if hours < 10 then result := "0" end result := result + hours.out + ":" if minutes < 10 then result := result + "0" end result := result + minutes.out + ":" if seconds < 10 then result := result + "0" end result := result + seconds.out end count: INTEGER is -- how many tracks are on the cd require valid_cdrom_handler: exists implies valid_handler do update_status result := get_numtracks_external (item) ensure count_correct: result = get_numtracks_external (item) end tracks: DS_LINKED_LIST [EM_CDROM_TRACK] is -- result is a linked list containing all tracks -- sorted from 1 .. count_track require valid_cdrom_handler: exists implies valid_handler local t: EM_CDROM_TRACK pointer: POINTER c, i: INTEGER do c := count pointer := get_track_external (item) create result.make from i := 0 until i = c loop -- This has to be done shared: SDL collects everything -- Not a nice way but it works perfectly create t.make_shared (pointer) pointer := pointer + t.sizeof Result.put_last (t) i := i + 1 end ensure result_not_void: result /= void end length: INTEGER is -- length of all audio tracks require valid_cdrom_handler: exists implies valid_handler local tracks_array: DS_LINKED_LIST [EM_CDROM_TRACK] cur_track: EM_CDROM_TRACK do tracks_array := tracks from tracks_array.start until tracks_array.after loop cur_track := tracks_array.item_for_iteration result := result + cur_track.length tracks_array.forth end end length_string: STRING is -- return an human readable length string (hh:mm:ss) require valid_cdrom_handler: exists implies valid_handler local len: INTEGER hours, minutes, seconds: INTEGER do create result.make_empty len := length seconds := len \\ 60 minutes := (len // 60) \\ 60 hours := (len // 3600) \\ 60 -- format the time in a human readable form (hh:mm:ss) if hours < 10 then result := "0" end result := result + hours.out + ":" if minutes < 10 then result := result + "0" end result := result + minutes.out + ":" if seconds < 10 then result := result + "0" end result := result + seconds.out end feature -- Cdrom status information is_empty: BOOLEAN is -- indicates if the drive is empty require valid_cdrom_handler: exists implies valid_handler do result := sdl_cdstatus_external (item) = Em_cdrom_empty end is_stopped: BOOLEAN is -- indicates if the drive is stopped require valid_cdrom_handler: exists implies valid_handler do result := sdl_cdstatus_external (item) = Em_cdrom_stopped end is_playing: BOOLEAN is -- indicates if the drive is currently playing a cd require valid_cdrom_handler: exists implies valid_handler do result := sdl_cdstatus_external (item) = Em_cdrom_playing end is_paused: BOOLEAN is -- indicates if the drive is paused require valid_cdrom_handler: exists implies valid_handler do result := sdl_cdstatus_external (item) = Em_cdrom_paused end is_erroneous: BOOLEAN is -- indicates if the drive has an error require valid_cdrom_handler: exists implies valid_handler do result := sdl_cdstatus_external (item) = Em_cdrom_error end has_cd_in_drive: BOOLEAN is -- indicates if the drive has an cd in it and has no errors require valid_cdrom_handler: exists implies valid_handler do result := sdl_cdstatus_external (item) > 0 end feature -- Additional cdrom structure information has_audio_track: BOOLEAN is -- check if this cd drive has an audio track require cd_in_drive: has_cd_in_drive local tracks_array: DS_LINKED_LIST [EM_CDROM_TRACK] cur_track: EM_CDROM_TRACK do tracks_array := tracks from tracks_array.start until tracks_array.after loop cur_track := tracks_array.item_for_iteration if cur_track.is_audio_track then result := true end tracks_array.forth end end has_data_track: BOOLEAN is -- check if this cd drive has a data track require cd_in_drive: has_cd_in_drive local tracks_array: DS_LINKED_LIST [EM_CDROM_TRACK] cur_track: EM_CDROM_TRACK do tracks_array := tracks from tracks_array.start until tracks_array.after loop cur_track := tracks_array.item_for_iteration if cur_track.is_data_track then result := true end tracks_array.forth end end feature -- Cdrom subsystem flags valid_handler: BOOLEAN -- Indicates if this CDRom handler (`current') is valid -- An invalid handler can be the result of following code -- create instance of EM_CDROM -- cdrom_subsystem.disable <-- from here the handler is invalid and can cause an segmentation fault -- -- cdrom_subsystem.enable feature {NONE} -- Implementation update_status is -- updaten status of the cdrom device -- this is needed to update informations of -- - id -- - current_track -- - current_time -- - count local status_code: INTEGER do -- returns the current status of the given drive status_code := sdl_cdstatus_external (item) end invariant cdrom_subsystem_enabled: cdrom_subsystem.is_enabled end