using Aaru.CommonTypes.Enums; using Aaru.CommonTypes.Interfaces; using ReactiveUI; namespace RedBookPlayer.Common.Discs { public abstract class OpticalDisc : ReactiveObject { #region Public Fields /// /// Indicate if the disc is ready to be used /// public bool Initialized { get; protected set; } = false; /// /// Current track number /// public abstract int CurrentTrackNumber { get; protected set; } /// /// Current track index /// public abstract ushort CurrentTrackIndex { get; protected set; } /// /// Current sector number /// public abstract ulong CurrentSector { get; set; } /// /// Represents the sector starting the section /// public ulong SectionStartSector { get => _sectionStartSector; protected set => this.RaiseAndSetIfChanged(ref _sectionStartSector, value); } /// /// Number of bytes per sector for the current track /// public int BytesPerSector => _image.Tracks[CurrentTrackNumber].TrackRawBytesPerSector; /// /// Represents the track type /// public TrackType TrackType { get; protected set; } /// /// Represents the total tracks on the disc /// public int TotalTracks { get; protected set; } = 0; /// /// Represents the total indices on the disc /// public int TotalIndexes { get; protected set; } = 0; /// /// Total sectors in the image /// public ulong TotalSectors => _image?.Info.Sectors ?? 0; /// /// Represents the time adjustment offset for the disc /// public ulong TimeOffset { get; protected set; } = 0; /// /// Represents the total playing time for the disc /// public ulong TotalTime { get; protected set; } = 0; private ulong _sectionStartSector; #endregion #region Protected State Variables /// /// Currently loaded disc image /// protected IOpticalMediaImage _image; #endregion /// /// Initialize the disc with a given image /// /// Aaruformat image to load /// True if playback should begin immediately, false otherwise public abstract void Init(IOpticalMediaImage image, bool autoPlay); #region Seeking /// /// Try to move to the next track, wrapping around if necessary /// public void NextTrack() { if(_image == null) return; CurrentTrackNumber++; LoadTrack(CurrentTrackNumber); } /// /// Try to move to the previous track, wrapping around if necessary /// /// True to play the hidden track, if it exists public void PreviousTrack(bool playHiddenTrack) { if(_image == null) return; if(CurrentSector < (ulong)_image.Tracks[CurrentTrackNumber].Indexes[1] + 75) { if(playHiddenTrack && CurrentTrackNumber == 0 && CurrentSector >= 75) CurrentSector = 0; else CurrentTrackNumber--; } else CurrentTrackNumber--; LoadTrack(CurrentTrackNumber); } /// /// Try to move to the next track index /// /// True if index changes can trigger a track change, false otherwise /// True if the track was changed, false otherwise public abstract bool NextIndex(bool changeTrack); /// /// Try to move to the previous track index /// /// True if index changes can trigger a track change, false otherwise /// True to play the hidden track, if it exists /// True if the track was changed, false otherwise public abstract bool PreviousIndex(bool changeTrack, bool playHiddenTrack); #endregion #region Helpers /// /// Load the first valid track in the image /// public abstract void LoadFirstTrack(); /// /// Read sector data from the base image starting from the current sector /// /// Current number of sectors to read /// Byte array representing the read sectors, if possible public byte[] ReadSectors(uint sectorsToRead) => _image.ReadSectors(CurrentSector, sectorsToRead); /// /// Set the total indexes from the current track /// public abstract void SetTotalIndexes(); /// /// Load the desired track, if possible /// /// Track number to load protected abstract void LoadTrack(int track); #endregion } }