From a189001d96c898928364889729e28ac633708eda Mon Sep 17 00:00:00 2001 From: Matt Nadareski Date: Fri, 29 Oct 2021 22:20:37 -0700 Subject: [PATCH] Redefine subchannel data for later (nw) --- RedBookPlayer.Models/Hardware/Player.cs | 92 ++++--------------- .../Hardware/SubchannelData.cs | 69 ++++++++++++++ .../Hardware/SubchannelPacket.cs | 89 ++++++++++++++++++ 3 files changed, 176 insertions(+), 74 deletions(-) create mode 100644 RedBookPlayer.Models/Hardware/SubchannelData.cs create mode 100644 RedBookPlayer.Models/Hardware/SubchannelPacket.cs diff --git a/RedBookPlayer.Models/Hardware/Player.cs b/RedBookPlayer.Models/Hardware/Player.cs index cda02de..639cc6c 100644 --- a/RedBookPlayer.Models/Hardware/Player.cs +++ b/RedBookPlayer.Models/Hardware/Player.cs @@ -1332,55 +1332,6 @@ namespace RedBookPlayer.Models.Hardware #region Helpers - /// - /// Reformat raw subchannel data for a single sector - /// - /// Raw subchannel data to format - /// Dictionary mapping subchannel to formatted data - public Dictionary ConvertSingleSubchannel(byte[] subchannelData) - { - if(subchannelData == null || subchannelData.Length != 96) - return null; - - // Create the output dictionary for the formatted data - Dictionary formattedData = new Dictionary - { - ['P'] = new byte[12], - ['Q'] = new byte[12], - ['R'] = new byte[12], - ['S'] = new byte[12], - ['T'] = new byte[12], - ['U'] = new byte[12], - ['V'] = new byte[12], - ['W'] = new byte[12], - }; - - // Loop through all bytes in the subchannel data and populate - int index = -1; - for(int i = 0; i < 96; i++) - { - // Get the modulo value of the current byte - int modValue = i % 8; - if(modValue == 0) - index++; - - // Retrieve the next byte - byte b = subchannelData[i]; - - // Set the respective bit in the new byte data - formattedData['P'][index] |= (byte)(HasBitSet(b, 7) ? 1 << (7 - modValue) : 0); - formattedData['Q'][index] |= (byte)(HasBitSet(b, 6) ? 1 << (7 - modValue) : 0); - formattedData['R'][index] |= (byte)(HasBitSet(b, 5) ? 1 << (7 - modValue) : 0); - formattedData['S'][index] |= (byte)(HasBitSet(b, 4) ? 1 << (7 - modValue) : 0); - formattedData['T'][index] |= (byte)(HasBitSet(b, 3) ? 1 << (7 - modValue) : 0); - formattedData['U'][index] |= (byte)(HasBitSet(b, 2) ? 1 << (7 - modValue) : 0); - formattedData['V'][index] |= (byte)(HasBitSet(b, 1) ? 1 << (7 - modValue) : 0); - formattedData['W'][index] |= (byte)(HasBitSet(b, 0) ? 1 << (7 - modValue) : 0); - } - - return formattedData; - } - /// /// Reformat raw subchannel data for multiple sectors /// @@ -1395,14 +1346,14 @@ namespace RedBookPlayer.Models.Hardware int modValue = subchannelData.Length / 96; Dictionary formattedData = new Dictionary { - ['P'] = new byte[12 * modValue], - ['Q'] = new byte[12 * modValue], - ['R'] = new byte[12 * modValue], - ['S'] = new byte[12 * modValue], - ['T'] = new byte[12 * modValue], - ['U'] = new byte[12 * modValue], - ['V'] = new byte[12 * modValue], - ['W'] = new byte[12 * modValue], + ['P'] = new byte[8 * modValue], + ['Q'] = new byte[8 * modValue], + ['R'] = new byte[8 * modValue], + ['S'] = new byte[8 * modValue], + ['T'] = new byte[8 * modValue], + ['U'] = new byte[8 * modValue], + ['V'] = new byte[8 * modValue], + ['W'] = new byte[8 * modValue], }; // Read in 96-byte chunks @@ -1410,29 +1361,22 @@ namespace RedBookPlayer.Models.Hardware { byte[] buffer = new byte[96]; Array.Copy(subchannelData, i * 96, buffer, 0, 96); - Dictionary singleData = ConvertSingleSubchannel(buffer); + var singleSubchannel = new SubchannelData(buffer); + Dictionary singleData = singleSubchannel.ConvertData(); - Array.Copy(singleData['P'], 0, formattedData['P'], 12 * i, 12); - Array.Copy(singleData['Q'], 0, formattedData['Q'], 12 * i, 12); - Array.Copy(singleData['R'], 0, formattedData['R'], 12 * i, 12); - Array.Copy(singleData['S'], 0, formattedData['S'], 12 * i, 12); - Array.Copy(singleData['T'], 0, formattedData['T'], 12 * i, 12); - Array.Copy(singleData['U'], 0, formattedData['U'], 12 * i, 12); - Array.Copy(singleData['V'], 0, formattedData['V'], 12 * i, 12); - Array.Copy(singleData['W'], 0, formattedData['W'], 12 * i, 12); + Array.Copy(singleData['P'], 0, formattedData['P'], 8 * i, 8); + Array.Copy(singleData['Q'], 0, formattedData['Q'], 8 * i, 8); + Array.Copy(singleData['R'], 0, formattedData['R'], 8 * i, 8); + Array.Copy(singleData['S'], 0, formattedData['S'], 8 * i, 8); + Array.Copy(singleData['T'], 0, formattedData['T'], 8 * i, 8); + Array.Copy(singleData['U'], 0, formattedData['U'], 8 * i, 8); + Array.Copy(singleData['V'], 0, formattedData['V'], 8 * i, 8); + Array.Copy(singleData['W'], 0, formattedData['W'], 8 * i, 8); } return formattedData; } - /// - /// Check if a bit is set in a byte - /// - /// Byte value to check - /// Index of the bit to check - /// True if the bit was set, false otherwise - private bool HasBitSet(byte value, int bitIndex) => (value & (1 << bitIndex)) != 0; - #endregion } } \ No newline at end of file diff --git a/RedBookPlayer.Models/Hardware/SubchannelData.cs b/RedBookPlayer.Models/Hardware/SubchannelData.cs new file mode 100644 index 0000000..93b2d24 --- /dev/null +++ b/RedBookPlayer.Models/Hardware/SubchannelData.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; + +namespace RedBookPlayer.Models.Hardware +{ + /// + /// Represents subchannel data for a single sector + /// + /// + internal class SubchannelData + { + public SubchannelPacket[] Packets { get; private set; } = new SubchannelPacket[4]; + + /// + /// Create a new subchannel data from a byte array + /// + public SubchannelData(byte[] bytes) + { + if(bytes == null || bytes.Length != 96) + return; + + byte[] buffer = new byte[24]; + for(int i = 0; i < 4; i++) + { + Array.Copy(bytes, 24 * i, buffer, 0, 24); + Packets[i] = new SubchannelPacket(buffer); + } + } + + /// + /// Convert the packet data into separate named subchannels + /// + public Dictionary ConvertData() + { + if(this.Packets == null || this.Packets.Length != 4) + return null; + + // Prepare the output formatted data + Dictionary formattedData = new Dictionary + { + ['P'] = new byte[8], + ['Q'] = new byte[8], + ['R'] = new byte[8], + ['S'] = new byte[8], + ['T'] = new byte[8], + ['U'] = new byte[8], + ['V'] = new byte[8], + ['W'] = new byte[8], + }; + + // Loop through all subchannel packets + for(int i = 0; i < 4; i++) + { + Dictionary singleData = Packets[i].ConvertData(); + + Array.Copy(singleData['P'], 0, formattedData['P'], 2 * i, 2); + Array.Copy(singleData['Q'], 0, formattedData['Q'], 2 * i, 2); + Array.Copy(singleData['R'], 0, formattedData['R'], 2 * i, 2); + Array.Copy(singleData['S'], 0, formattedData['S'], 2 * i, 2); + Array.Copy(singleData['T'], 0, formattedData['T'], 2 * i, 2); + Array.Copy(singleData['U'], 0, formattedData['U'], 2 * i, 2); + Array.Copy(singleData['V'], 0, formattedData['V'], 2 * i, 2); + Array.Copy(singleData['W'], 0, formattedData['W'], 2 * i, 2); + } + + return formattedData; + } + } +} \ No newline at end of file diff --git a/RedBookPlayer.Models/Hardware/SubchannelPacket.cs b/RedBookPlayer.Models/Hardware/SubchannelPacket.cs new file mode 100644 index 0000000..2051439 --- /dev/null +++ b/RedBookPlayer.Models/Hardware/SubchannelPacket.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; + +namespace RedBookPlayer.Models.Hardware +{ + /// + /// Represents a single packet of subcode data + /// + /// + internal class SubchannelPacket + { + public byte Command { get; private set; } + public byte Instruction { get; private set; } + public byte[] ParityQ { get; private set; } = new byte[2]; + public byte[] Data { get; private set; } = new byte[16]; + public byte[] ParityP { get; private set; } = new byte[4]; + + /// + /// Create a new subchannel packet from a byte array + /// + public SubchannelPacket(byte[] bytes) + { + if(bytes == null || bytes.Length != 24) + return; + + this.Command = bytes[0]; + this.Instruction = bytes[1]; + + Array.Copy(bytes, 2, this.ParityQ, 0, 2); + Array.Copy(bytes, 4, this.Data, 0, 16); + Array.Copy(bytes, 20, this.ParityP, 0, 4); + } + + /// + /// Convert the data into separate named subchannels + /// + public Dictionary ConvertData() + { + if(this.Data == null || this.Data.Length != 16) + return null; + + // Create the output dictionary for the formatted data + Dictionary formattedData = new Dictionary + { + ['P'] = new byte[2], + ['Q'] = new byte[2], + ['R'] = new byte[2], + ['S'] = new byte[2], + ['T'] = new byte[2], + ['U'] = new byte[2], + ['V'] = new byte[2], + ['W'] = new byte[2], + }; + + // Loop through all bytes in the subchannel data and populate + int index = -1; + for(int i = 0; i < 16; i++) + { + // Get the modulo value of the current byte + int modValue = i % 8; + if(modValue == 0) + index++; + + // Retrieve the next byte + byte b = this.Data[i]; + + // Set the respective bit in the new byte data + formattedData['P'][index] |= (byte)(HasBitSet(b, 7) ? 1 << (7 - modValue) : 0); + formattedData['Q'][index] |= (byte)(HasBitSet(b, 6) ? 1 << (7 - modValue) : 0); + formattedData['R'][index] |= (byte)(HasBitSet(b, 5) ? 1 << (7 - modValue) : 0); + formattedData['S'][index] |= (byte)(HasBitSet(b, 4) ? 1 << (7 - modValue) : 0); + formattedData['T'][index] |= (byte)(HasBitSet(b, 3) ? 1 << (7 - modValue) : 0); + formattedData['U'][index] |= (byte)(HasBitSet(b, 2) ? 1 << (7 - modValue) : 0); + formattedData['V'][index] |= (byte)(HasBitSet(b, 1) ? 1 << (7 - modValue) : 0); + formattedData['W'][index] |= (byte)(HasBitSet(b, 0) ? 1 << (7 - modValue) : 0); + } + + return formattedData; + } + + /// + /// Check if a bit is set in a byte + /// + /// Byte value to check + /// Index of the bit to check + /// True if the bit was set, false otherwise + private bool HasBitSet(byte value, int bitIndex) => (value & (1 << bitIndex)) != 0; + } +} \ No newline at end of file