Skip to content

Commit

Permalink
Prepare for release (#16)
Browse files Browse the repository at this point in the history
* add import sound

* working sound effect replacement

* add export/import of all images in an object

* add track object image names

* cleaning up ui

* allow saving sound objects

* add checksum to original objects file

* start cleaning up object definitions, adding all attributes

* cleanup a few objects, add image string names to interface object

* more objects to records

* add basic implementation of vehicle rotator

* add start of vehicle rotator/viewer page

* add image ids for trackextra object

* add comment

* trackextra ids account for tab preview

* trackobject -> record
  • Loading branch information
LeftofZen authored Feb 6, 2024
1 parent e2b6e0f commit b14ecd8
Show file tree
Hide file tree
Showing 46 changed files with 3,510 additions and 1,392 deletions.
5 changes: 5 additions & 0 deletions OpenLocoTool/DatFileParsing/LocoAttributes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ public class LocoStructSkipReadAttribute : Attribute
public class LocoStringAttribute : Attribute
{ }

// basically a 'skip' attribute to allow deferred loading for variable data, and writing of this property will be 0
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property, AllowMultiple = false)]
public class LocoImageIdAttribute : Attribute
{ }

// to mark properties that seemingly have no purpose or use
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property, AllowMultiple = false)]
public class LocoPropertyMaybeUnused : Attribute
Expand Down
21 changes: 16 additions & 5 deletions OpenLocoTool/DatFileParsing/SawyerStreamReader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

namespace OpenLocoTool.DatFileParsing
{

public static class SawyerStreamReader
{
public static List<S5Header> LoadVariableCountS5Headers(ReadOnlySpan<byte> data, int count)
Expand Down Expand Up @@ -125,6 +124,12 @@ public static (DatFileInfo DatFileInfo, ILocoObject LocoObject) LoadFullObjectFr
logger?.Error(ex, "Error loading graphics table");
}

// some objects have variable-sized data
if (loadExtra && locoStruct is ILocoStructPostLoad locoStructPostLoad)
{
locoStructPostLoad.PostLoad();
}

// add to object manager
SObjectManager.Add(newObj);

Expand Down Expand Up @@ -186,8 +191,13 @@ public static (StringTable table, int bytesRead) LoadStringTable(ReadOnlySpan<by
return LoadStringTable(data, stringTableStrings);
}

public static G1Dat LoadG1(string filename, ILogger? logger = null)
public static G1Dat? LoadG1(string filename, ILogger? logger = null)
{
if (!File.Exists(filename))
{
logger?.Debug($"File {filename} does not exist");
return null;
}
ReadOnlySpan<byte> fullData = LoadBytesFromFile(filename);
var (g1Header, imageTable, imageTableBytesRead) = LoadImageTable(fullData);
logger?.Info($"FileLength={new FileInfo(filename).Length} NumEntries={g1Header.NumEntries} TotalSize={g1Header.TotalSize} ImageTableLength={imageTableBytesRead}");
Expand Down Expand Up @@ -368,7 +378,7 @@ public static ILocoStruct GetLocoStruct(ObjectType objectType, ReadOnlySpan<byte
_ => throw new InvalidDataException("Unknown chunk encoding scheme"),
};

public static (RiffWavHeader header, byte[] data) LoadMusicTrack(byte[] data)
public static (RiffWavHeader header, byte[] data) LoadWavFile(byte[] data)
{
using (var ms = new MemoryStream(data))
using (var br = new BinaryReader(ms))
Expand All @@ -391,6 +401,7 @@ public static (RiffWavHeader header, byte[] data) LoadMusicTrack(byte[] data)
{
var numSounds = br.ReadUInt32();
var soundOffsets = new uint32_t[numSounds];

for (var i = 0; i < numSounds; ++i)
{
soundOffsets[i] = br.ReadUInt32();
Expand All @@ -400,10 +411,10 @@ public static (RiffWavHeader header, byte[] data) LoadMusicTrack(byte[] data)
{
br.BaseStream.Position = soundOffsets[i];
var pcmLen = br.ReadUInt32();
var format = ByteReader.ReadLocoStruct<WaveFormatEx>(br.ReadBytes(ObjectAttributes.StructSize<WaveFormatEx>()));
var header = ByteReader.ReadLocoStruct<WaveFormatEx>(br.ReadBytes(ObjectAttributes.StructSize<WaveFormatEx>()));

var pcmData = br.ReadBytes((int)pcmLen);
result.Add((format, pcmData));
result.Add((header, pcmData));
}
}

Expand Down
79 changes: 73 additions & 6 deletions OpenLocoTool/DatFileParsing/SawyerStreamWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,81 @@ namespace OpenLocoTool.DatFileParsing
{
public static class SawyerStreamWriter
{
public static void ExportSoundEffectAsWave(string filename, WaveFormatEx header, byte[] pcmData)
//public static void ExportSoundEffectAsWave(string filename, WaveFormatEx header, byte[] pcmData)
//{
// using (var stream = File.Create(filename))
// {
// stream.Write(ByteWriter.WriteLocoStruct(header));
// stream.Write(pcmData);
// stream.Flush();
// stream.Close();
// }
//}

public static RiffWavHeader WaveFormatExToRiff(WaveFormatEx hdr, int pcmDataLength)
=> new(
0x46464952, // "RIFF"
(uint)(pcmDataLength + 36), // file size
0x45564157, // "WAVE"
0x20746d66, // "fmt "
16, // size of fmt chunk
1, // format tag
(ushort)hdr.NumberOfChannels,
(uint)hdr.SampleRate,
(uint)hdr.AverageBytesPerSecond,
4, //(ushort)waveFHeader.BlockAlign,
16, //(ushort)waveFHeader.BitsPerSample,
0x61746164, // "data"
(uint)pcmDataLength // data size
);

public static WaveFormatEx RiffToWaveFormatEx(RiffWavHeader hdr)
=> new(1, (short)hdr.NumberOfChannels, (int)hdr.SampleRate, (int)hdr.ByteRate, 2, 16, 0);
//0x46464952, // "RIFF"
//(uint)(pcmDataLength + 36), // file size
//0x45564157, // "WAVE"
//0x20746d66, // "fmt "
//16, // size of fmt chunk
//1, // format tag
//(ushort)hdr.NumberOfChannels,
//(uint)hdr.SampleRate,
//(uint)hdr.AverageBytesPerSecond,
//4, //(ushort)waveFHeader.BlockAlign,
//16, //(ushort)waveFHeader.BitsPerSample,
//0x61746164, // "data"
//(uint)pcmDataLength // data size
//);

public static byte[] SaveSoundEffectsToCSS(List<(RiffWavHeader header, byte[] data)> sounds)
{
using (var stream = File.Create(filename))
using (var ms = new MemoryStream())
using (var br = new BinaryWriter(ms))
{
stream.Write(ByteWriter.WriteLocoStruct(header));
stream.Write(pcmData);
stream.Flush();
stream.Close();
// total sounds
br.Write((uint)sounds.Count);

var currOffset = 4 + (sounds.Count * 4); // 4 for sound count, then 32 sounds each have a 4-byte offset. its always 33 * 4 = 132 to start.

// sound offsets
foreach (var sfx in sounds)
{
br.Write((uint)currOffset);
currOffset += 4 + sfx.data.Length + ObjectAttributes.StructSize<WaveFormatEx>();
}

// pcm data
foreach (var sfx in sounds)
{
var waveHdr = RiffToWaveFormatEx(sfx.header);
br.Write((uint)sfx.data.Length);
br.Write(ByteWriter.WriteLocoStruct(waveHdr));
br.Write(sfx.data);
}

ms.Flush();
ms.Close();

return ms.ToArray();
}
}

Expand Down
12 changes: 7 additions & 5 deletions OpenLocoTool/Data/OriginalDataFiles.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ public static class OriginalDataFiles
{ "20s4.dat", "Flying High" },
{ "20s5.dat", "Get Me To Gladstone Bay" },
{ "20s6.dat", "Sandy Track Blues" },
{ "40s1.dat", "A Traveller's Serenade" }, // in loco its misspelt - Seranade
{ "40s1.dat", "A Traveller's Serenade" }, // todo: in loco its misspelt - Seranade
{ "40s2.dat", "Latino Trip" },
{ "40s3.dat", "Head To The Bop" },
{ "50s1.dat", "Gettin' On The Gas" },
Expand All @@ -36,10 +36,12 @@ public static class OriginalDataFiles
{ "90s2.dat", "Everlasting High-Rise" },
};

public static readonly Dictionary<string, string> SoundEffects = new()
{
{ "css1.dat", "Sound Effects" },
};
public const string SoundEffect = "css1.dat";

//public static readonly Dictionary<string, string> SoundEffect = new()
//{
// { "css1.dat", "Sound Effects" },
//};

public static readonly Dictionary<string, string> MiscellaneousTracks = new()
{
Expand Down
Loading

0 comments on commit b14ecd8

Please sign in to comment.