Add PlayJ models

This commit is contained in:
Matt Nadareski
2023-01-14 21:43:59 -08:00
parent 12fdae7944
commit cb3c666f64
9 changed files with 397 additions and 78 deletions

View File

@@ -0,0 +1,29 @@
namespace BurnOutSharp.Models.PlayJ
{
/// <summary>
/// PlayJ audio file / CDS entry
/// <summary>
public sealed class AudioFile
{
/// <summary>
/// Header
/// </summary>
public EntryHeader Header { get; set; }
/// <summary>
/// Unknown block 1
/// </summary>
public UnknownBlock1 UnknownBlock1 { get; set; }
/// <summary>
/// Value referred to by <see cref="EntryHeader.UnknownOffset2"/>
/// </summary>
/// <remarks>Typically 0x00000000</remarks>
public uint UnknownValue2 { get; set; }
/// <summary>
/// Unknown block 3
/// </summary>
public UnknownBlock3 UnknownBlock3 { get; set; }
}
}

View File

@@ -0,0 +1,9 @@
namespace BurnOutSharp.Models.PlayJ
{
public static class Constants
{
public static readonly byte[] SignatureBytes = new byte[] { 0xFF, 0x9D, 0x53, 0x4B };
public const uint SignatureUInt32 = 0x4B539DFF;
}
}

View File

@@ -0,0 +1,170 @@
namespace BurnOutSharp.Models.PlayJ
{
/// <summary>
/// PlayJ audio header / CDS entry header
/// </summary>
/// <remarks>This is only valid for V1 right now</remarks>
public sealed class EntryHeader
{
/// <summary>
/// Signature (0x4B539DFF)
/// </summary>
public uint Signature;
/// <summary>
/// Version
/// </summary>
public uint Version;
/// <summary>
/// Download track ID
/// </summary>
/// <remarks>0xFFFFFFFF if unset</remarks>
public uint TrackID;
/// <summary>
/// Offset to unknown data block 1
/// </summary>
public uint UnknownOffset1;
/// <summary>
/// Offset to unknown data block 2
/// </summary>
public uint UnknownOffset2;
/// <summary>
/// Offset to unknown data block 3
/// </summary>
public uint UnknownOffset3;
/// <summary>
/// Unknown
/// </summary>
/// <remarks>Always 0x00000001</remarks>
public uint Unknown1;
/// <summary>
/// Unknown
/// </summary>
/// <remarks>Typically 0x00000001 in download titles</remarks>
public uint Unknown2;
/// <summary>
/// Track year
/// </summary>
/// <remarks>0xFFFFFFFF if unset</remarks>
public uint Year;
/// <summary>
/// Track number
/// </summary>
public byte TrackNumber;
/// <summary>
/// Subgenre
/// </summary>
public Subgenre Subgenre;
/// <summary>
/// Track duration in seconds
/// </summary>
public uint Duration;
/// <summary>
/// Length of the track name
/// </summary>
public ushort TrackLength;
/// <summary>
/// Track name (not null-terminated)
/// </summary>
public string Track;
/// <summary>
/// Length of the artist name
/// </summary>
public ushort ArtistLength;
/// <summary>
/// Artist name (not null-terminated)
/// </summary>
public string Artist;
/// <summary>
/// Length of the album name
/// </summary>
public ushort AlbumLength;
/// <summary>
/// Album name (not null-terminated)
/// </summary>
public string Album;
/// <summary>
/// Length of the writer name
/// </summary>
public ushort WriterLength;
/// <summary>
/// Writer name (not null-terminated)
/// </summary>
public string Writer;
/// <summary>
/// Length of the publisher name
/// </summary>
public ushort PublisherLength;
/// <summary>
/// Publisher name (not null-terminated)
/// </summary>
public string Publisher;
/// <summary>
/// Length of the label name
/// </summary>
public ushort LabelLength;
/// <summary>
/// Label name (not null-terminated)
/// </summary>
public string Label;
/// <summary>
/// Length of the comments
/// </summary>
/// <remarks>Optional field only in some samples</remarks>
public ushort CommentsLength;
/// <summary>
/// Comments (not null-terminated)
/// </summary>
/// <remarks>Optional field only in some samples</remarks>
public string Comments;
#region V2 Notes
// Header Layout (V2) [WIP]
// ------------------------------------------------------------------------------
// 0x00 Signature UInt32
// 0x04 Version UInt32 [0x0000000A]
// 0x08 UNKNOWN byte[36]
// 0x2A Track Length UInt16
// 0x2C Track String
// 0x2C+TL Artist Length UInt16
// 0x2E+TL Artist String
// 0x2E+TL+TAL Album Length UInt16
// 0x30+TL+TAL Album String
// 0x30+TL+TAL+AL Writer Length UInt16
// 0x32+TL+TAL+AL Writer String
// 0x32+TL+TAL+AL+WL Publisher Length UInt16
// 0x34+TL+TAL+AL+WL Publisher String
// 0x34+TL+TAL+AL+WL+PL Label Length UInt16
// 0x36+TL+TAL+AL+WL+PL Label String
// In the third block:
// lady.plj has 0x00000002 and references "ad006376_5.dat" after
#endregion
}
}

View File

@@ -0,0 +1,122 @@
namespace BurnOutSharp.Models.PlayJ
{
/// <see href="http://www.playj.com/static/genreindex_XX.html"/>
public enum Genre
{
/// <summary>
/// Blues/Folk/Country
/// </summary>
BluesFolkCountry = 1,
/// <summary>
/// Jazz
/// </summary>
Jazz = 5,
/// <summary>
/// Reggae
/// </summary>
Reggae = 10,
/// <summary>
/// Classical
/// </summary>
Classical = 12,
/// <summary>
/// Electronic
/// </summary>
Electronic = 13,
/// <summary>
/// Pop/Rock
/// </summary>
PopRock = 15,
/// <summary>
/// World
/// </summary>
World = 16,
/// <summary>
/// Urban
/// </summary>
Urban = 17,
/// <summary>
/// Latin
/// </summary>
Latin = 18,
/// <summary>
/// Soundtrack/Other
/// </summary>
SoundtrackOther = 20,
/// <summary>
/// New Age
/// </summary>
NewAge = 21,
/// <summary>
/// Spiritual
/// </summary>
Spiritual = 22,
/// <summary>
/// Sway & Tech
/// </summary>
SwayAndTech = 23,
/// <summary>
/// Jam Bands
/// </summary>
JamBands = 24,
/// <summary>
/// Comedy
/// </summary>
Comedy = 25,
/// <summary>
/// Brazilian
/// </summary>
Brazilian = 26,
}
// TODO: Fill out the remaining subgenres from the wayback machine
/// <see href="http://playj.com/static/subgenre_XX.html"/>
/// <remarks>Every subgenre is uniquely associated with a genre</remarks>
public enum Subgenre : byte
{
/// <summary>
/// Blues/Folk/Country > Blues (Modern/Electric)
/// </summary>
BluesModernElectric = 2,
/// <summary>
/// Blues/Folk/Country > Blues (Modern/Acoustic)
/// </summary>
BluesModernAcoustic = 3,
/// <summary>
/// Blues/Folk/Country > Blues (Traditional)
/// </summary>
BluesTraditional = 4,
/// <summary>
/// Blues/Folk/Country > Folk (Traditional)
/// </summary>
FolkTraditional = 5,
/// <summary>
/// Blues/Folk/Country > Folk (Contemporary)
/// </summary>
FolkContemporary = 6,
/// <summary>
/// Blues/Folk/Country > Folk (Jazz)
/// </summary>
FolkJazz = 7,
}
}

View File

@@ -0,0 +1,18 @@
namespace BurnOutSharp.Models.PlayJ
{
/// <summary>
/// PlayJ playlist file
/// </summary>
public sealed class Playlist
{
/// <summary>
/// Playlist header
/// </summary>
public PlaylistHeader PlaylistHeader { get; set; }
/// <summary>
/// Entry headers
/// </summary>
public EntryHeader[] EntryHeaders { get; set; }
}
}

View File

@@ -0,0 +1,18 @@
namespace BurnOutSharp.Models.PlayJ
{
/// <summary>
/// PlayJ playlist header
/// </summary>
public sealed class PlaylistHeader
{
/// <summary>
/// Number of tracks contained within the playlist
/// </summary>
public uint TrackCount;
/// <summary>
/// 52 bytes of unknown data
/// </summary>
public byte[] Data;
}
}

View File

@@ -0,0 +1,18 @@
namespace BurnOutSharp.Models.PlayJ
{
/// <summary>
/// Data referred to by <see cref="EntryHeader.UnknownOffset1"/>
/// </summary>
public sealed class UnknownBlock1
{
/// <summary>
/// Length of the following data block
/// </summary>
public ushort Length;
/// <summary>
/// Unknown data
/// </summary>
public byte[] Data;
}
}

View File

@@ -0,0 +1,13 @@
namespace BurnOutSharp.Models.PlayJ
{
/// <summary>
/// Data referred to by <see cref="EntryHeader.UnknownOffset3"/>
/// </summary>
public sealed class UnknownBlock3
{
/// <summary>
/// Unknown data
/// </summary>
public byte[] Data;
}
}

View File

@@ -37,84 +37,6 @@ namespace BurnOutSharp.FileType
AppendToDictionary(protections, file, "PlayJ Audio File");
return protections;
}
// Header Layout (V1)
// ------------------------------------------------------------------------------
// 0x00 Signature UInt32
// 0x04 Version UInt32 [0x00000000]
// 0x08 Track ID UInt32 [Always 0xFFFFFFFF in CD titles]
// 0x0C Unknown Offset 1 UInt32
// 0x10 Unknown Offset 2 UInt32
// 0x14 Unknown Offset 3 UInt32
// 0x18 Unknown (Initial play count?) UInt32 [Always 0x00000001]
// 0x1C Unknown (Play count?) UInt32 [Always 0x00000001 in download titles]
// 0x20 Year UInt32 [0xFFFFFFFF if unset]
// 0x24 Track Number Byte
// 0x25 Subgenre Byte
// 0x26 Duration in Seconds UInt32
// 0x2A Track Length UInt16
// 0x2C Track String
// 0x2C+TL Artist Length UInt16
// 0x2E+TL Artist String
// 0x2E+TL+TAL Album Length UInt16
// 0x30+TL+TAL Album String
// 0x30+TL+TAL+AL Writer Length UInt16
// 0x32+TL+TAL+AL Writer String
// 0x32+TL+TAL+AL+WL Publisher Length UInt16
// 0x34+TL+TAL+AL+WL Publisher String
// 0x34+TL+TAL+AL+WL+PL Label Length UInt16
// 0x36+TL+TAL+AL+WL+PL Label String
//
// The following samples also have a "Comments" section after the label, same format
// - golden_empire.plj
// - i_want_to_take_you_higher.plj
//
// Unknown Offset 1
// ------------------------------------------------------------------------------
// UO1 Unknown Block 1 Length UInt32
// UO1+2 Unknown Block 1 byte[UB1L]
//
// Unknown Offset 2
// ------------------------------------------------------------------------------
// UO2 Unknown Value UInt32
// Most of the samples have 0x00000000
// nature_soundscape_v.plj has 0x00C88028
//
// Unknown Offset 3
// ------------------------------------------------------------------------------
// UO3 Unknown Data byte[??]
//
// Header Layout (V2) [WIP]
// ------------------------------------------------------------------------------
// 0x00 Signature UInt32
// 0x04 Version UInt32 [0x0000000A]
// 0x08 UNKNOWN byte[36]
// 0x2A Track Length UInt16
// 0x2C Track String
// 0x2C+TL Artist Length UInt16
// 0x2E+TL Artist String
// 0x2E+TL+TAL Album Length UInt16
// 0x30+TL+TAL Album String
// 0x30+TL+TAL+AL Writer Length UInt16
// 0x32+TL+TAL+AL Writer String
// 0x32+TL+TAL+AL+WL Publisher Length UInt16
// 0x34+TL+TAL+AL+WL Publisher String
// 0x34+TL+TAL+AL+WL+PL Label Length UInt16
// 0x36+TL+TAL+AL+WL+PL Label String
// In the third block:
// lady.plj has 0x00000002 and references "ad006376_5.dat" after
// Known Subgenre IDs (http://playj.com/static/subgenre_XX.html)
// -----------------------------------------------
// 2 - Blues/Folk/Country > Blues (Modern/Electric)
// 3 - Blues/Folk/Country > Blues (Modern/Acoustic)
// 4 - Blues/Folk/Country > Blues (Traditional)
// 5 - Blues/Folk/Country > Folk (Traditional)
// 6 - Blues/Folk/Country > Folk (Contemporary)
// 7 - Blues/Folk/Country > Folk (Jazz)
// TODO: When converting to enum, fill in the rest
}
catch (Exception ex)
{