diff --git a/RedBookPlayer/PlayableDisc.cs b/RedBookPlayer/PlayableDisc.cs
index 36c0e17..9f22e8e 100644
--- a/RedBookPlayer/PlayableDisc.cs
+++ b/RedBookPlayer/PlayableDisc.cs
@@ -2,8 +2,8 @@ using System;
using System.Collections.Generic;
using System.Linq;
using Aaru.CommonTypes.Enums;
+using Aaru.CommonTypes.Interfaces;
using Aaru.CommonTypes.Structs;
-using Aaru.DiscImages;
using Aaru.Helpers;
using static Aaru.Decoders.CD.FullTOC;
@@ -44,32 +44,16 @@ namespace RedBookPlayer
// Cache the current track for easy access
Track track = _image.Tracks[CurrentTrackNumber];
- // Set new track-specific data
- byte[] flagsData = _image.ReadSectorTag(track.TrackSequence, SectorTagType.CdTrackFlags);
- ApplyDeEmphasis = ((CdFlags)flagsData[0]).HasFlag(CdFlags.PreEmphasis);
+ // Set track flags from subchannel data, if possible
+ SetTrackFlags(track);
- try
- {
- byte[] subchannel = _image.ReadSectorTag(track.TrackStartSector, SectorTagType.CdSectorSubchannel);
-
- if(!ApplyDeEmphasis)
- ApplyDeEmphasis = (subchannel[3] & 0b01000000) != 0;
-
- CopyAllowed = (subchannel[2] & 0b01000000) != 0;
- TrackType = (subchannel[1] & 0b01000000) != 0 ? Aaru.CommonTypes.Enums.TrackType.Data : Aaru.CommonTypes.Enums.TrackType.Audio;
- }
- catch(ArgumentException)
- {
- TrackType = track.TrackType;
- }
-
- TrackHasEmphasis = ApplyDeEmphasis;
+ ApplyDeEmphasis = TrackHasEmphasis;
TotalIndexes = track.Indexes.Keys.Max();
CurrentTrackIndex = track.Indexes.Keys.Min();
// If we're not playing data tracks, skip
- if(!App.Settings.PlayDataTracks && TrackType != Aaru.CommonTypes.Enums.TrackType.Audio)
+ if(!App.Settings.PlayDataTracks && TrackType != TrackType.Audio)
{
if(increment)
NextTrack();
@@ -157,19 +141,24 @@ namespace RedBookPlayer
public bool TrackHasEmphasis { get; private set; } = false;
///
- /// Indicates if de-emphasis should be applied
+ /// Represents the PRE flag
///
public bool ApplyDeEmphasis { get; private set; } = false;
///
- /// Represents the copy allowed flag
+ /// Represents the DCP flag
///
public bool CopyAllowed { get; private set; } = false;
///
/// Represents the track type
///
- public TrackType? TrackType { get; private set; }
+ public TrackType TrackType { get; private set; }
+
+ ///
+ /// Represents the 4CH flag
+ ///
+ public bool QuadChannel { get; private set; } = false;
///
/// Represents the sector starting the section
@@ -208,7 +197,7 @@ namespace RedBookPlayer
///
/// Currently loaded disc image
///
- private AaruFormat _image;
+ private IOpticalMediaImage _image;
///
/// Current track number
@@ -237,7 +226,7 @@ namespace RedBookPlayer
///
/// Aaruformat image to load
/// True if playback should begin immediately, false otherwise
- public void Init(AaruFormat image, bool autoPlay = false)
+ public void Init(IOpticalMediaImage image, bool autoPlay = false)
{
// If the image is null, we can't do anything
if(image == null)
@@ -657,6 +646,89 @@ namespace RedBookPlayer
CurrentSector = (ulong)(firstSector >= 0 ? firstSector : _image.Tracks[track].Indexes[1]);
}
+ ///
+ /// Set default track flags for the current track
+ ///
+ /// Track object to read from
+ private void SetDefaultTrackFlags(Track track)
+ {
+ QuadChannel = false;
+ TrackType = track.TrackType;
+ CopyAllowed = false;
+ TrackHasEmphasis = false;
+ }
+
+ ///
+ /// Set track flags from the current track
+ ///
+ /// Track object to read from
+ private void SetTrackFlags(Track track)
+ {
+ try
+ {
+ ulong currentSector = track.TrackStartSector;
+ for (int i = 0; i < 16; i++)
+ {
+ // Try to read the subchannel
+ byte[] subBuf = _image.ReadSectorTag(track.TrackStartSector, SectorTagType.CdSectorSubchannel);
+ if(subBuf == null || subBuf.Length < 4)
+ return;
+
+ // Check the expected track, if possible
+ int adr = subBuf[0] & 0x0F;
+ if(adr == 1)
+ {
+ if(subBuf[1] > track.TrackSequence)
+ {
+ currentSector--;
+ continue;
+ }
+ else if(subBuf[1] < track.TrackSequence)
+ {
+ currentSector++;
+ continue;
+ }
+ }
+
+ // Set the track flags from subchannel data
+ int control = (subBuf[0] & 0xF0) / 16;
+ switch((control & 0xC) / 4)
+ {
+ case 0:
+ QuadChannel = false;
+ TrackType = TrackType.Audio;
+ TrackHasEmphasis = (control & 0x01) == 1;
+ break;
+ case 1:
+ QuadChannel = false;
+ TrackType = TrackType.Data;
+ TrackHasEmphasis = false;
+ break;
+ case 2:
+ QuadChannel = true;
+ TrackType = TrackType.Audio;
+ TrackHasEmphasis = (control & 0x01) == 1;
+ break;
+ default:
+ QuadChannel = false;
+ TrackType = track.TrackType;
+ TrackHasEmphasis = false;
+ break;
+ }
+
+ CopyAllowed = (control & 0x02) > 0;
+ return;
+ }
+
+ // If we didn't find subchannel data, assume defaults
+ SetDefaultTrackFlags(track);
+ }
+ catch(Exception)
+ {
+ SetDefaultTrackFlags(track);
+ }
+ }
+
#endregion
}
}
diff --git a/RedBookPlayer/PlayerView.xaml b/RedBookPlayer/PlayerView.xaml
index 7b0f528..2213eba 100644
--- a/RedBookPlayer/PlayerView.xaml
+++ b/RedBookPlayer/PlayerView.xaml
@@ -94,6 +94,8 @@
EMPHASIS
COPY
COPY
+ 4CH
+ 4CH
HIDDEN
HIDDEN
diff --git a/RedBookPlayer/PlayerView.xaml.cs b/RedBookPlayer/PlayerView.xaml.cs
index f5ac532..095e332 100644
--- a/RedBookPlayer/PlayerView.xaml.cs
+++ b/RedBookPlayer/PlayerView.xaml.cs
@@ -5,6 +5,7 @@ using System.Linq;
using System.Threading.Tasks;
using System.Timers;
using Aaru.CommonTypes.Enums;
+using Aaru.CommonTypes.Interfaces;
using Aaru.DiscImages;
using Aaru.Filters;
using Avalonia;
@@ -199,16 +200,12 @@ namespace RedBookPlayer
///
/// Aaruformat image file
/// True if the image is playble, false otherwise
- private bool IsPlayableImage(AaruFormat image)
+ private bool IsPlayableImage(IOpticalMediaImage image)
{
// Invalid images can't be played
if (image == null)
return false;
- // Tape images are not supported
- if (image.IsTape)
- return false;
-
// Determine based on media type
// TODO: Can we be more granular with sub types?
(string type, string _) = Aaru.CommonTypes.Metadata.MediaType.MediaTypeToString(image.Info.MediaType);
@@ -278,6 +275,7 @@ namespace RedBookPlayer
dataContext.ApplyDeEmphasis = PlayableDisc.ApplyDeEmphasis;
dataContext.TrackHasEmphasis = PlayableDisc.TrackHasEmphasis;
dataContext.CopyAllowed = PlayableDisc.CopyAllowed;
+ dataContext.QuadChannel = PlayableDisc.QuadChannel;
dataContext.IsAudioTrack = PlayableDisc.TrackType == TrackType.Audio;
dataContext.IsDataTrack = PlayableDisc.TrackType != TrackType.Audio;
}
diff --git a/RedBookPlayer/PlayerViewModel.cs b/RedBookPlayer/PlayerViewModel.cs
index a44dcc4..17e058f 100644
--- a/RedBookPlayer/PlayerViewModel.cs
+++ b/RedBookPlayer/PlayerViewModel.cs
@@ -32,6 +32,13 @@ namespace RedBookPlayer
set => this.RaiseAndSetIfChanged(ref _copyAllowed, value);
}
+ private bool _quadChannel;
+ public bool QuadChannel
+ {
+ get => _quadChannel;
+ set => this.RaiseAndSetIfChanged(ref _quadChannel, value);
+ }
+
private bool _isAudioTrack;
public bool IsAudioTrack
{