Skip to content

Commit

Permalink
Added IFF sample loader as helper method.
Browse files Browse the repository at this point in the history
  • Loading branch information
neumatho committed Feb 1, 2025
1 parent 931d3cb commit 1dd1eab
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 92 deletions.
101 changes: 12 additions & 89 deletions Source/Agents/Players/IffSmus/Instruments/FormFormat.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using Polycode.NostalgicPlayer.Kit.Containers;
using Polycode.NostalgicPlayer.Kit.Interfaces;
using Polycode.NostalgicPlayer.Kit.Streams;
using Polycode.NostalgicPlayer.Kit.Utility;

namespace Polycode.NostalgicPlayer.Agent.Player.IffSmus.Instruments
{
Expand All @@ -19,7 +20,8 @@ namespace Polycode.NostalgicPlayer.Agent.Player.IffSmus.Instruments
/// </summary>
internal class FormFormat : IInstrumentFormat
{
private FormData formatData;
private IffSample formatData;
private ushort numberOfHiOctavesToSkip;

/********************************************************************/
/// <summary>
Expand Down Expand Up @@ -47,88 +49,9 @@ public bool Load(ModuleStream instrumentStream, PlayerFileInfo fileInfo, string

instrumentStream.Seek(0, SeekOrigin.Begin);

if (instrumentStream.Read_B_UINT32() != 0x464f524d) // FORM
{
errorMessage = string.Format(Resources.IDS_SMUS_ERR_LOADING_READ_EXTERNAL_FILE, instrumentFileName);
return false;
}

uint formLength = instrumentStream.Read_B_UINT32();

if (instrumentStream.Read_B_UINT32() != 0x38535658) // 8SVX
{
errorMessage = string.Format(Resources.IDS_SMUS_ERR_LOADING_READ_EXTERNAL_FILE, instrumentFileName);
return false;
}

formLength -= 4;

formatData = new FormData();

while (formLength > 0)
{
uint chunkName = instrumentStream.Read_B_UINT32();
uint chunkLength = instrumentStream.Read_B_UINT32();
formLength -= 8;

if ((chunkLength % 2) != 0)
chunkLength++;

switch (chunkName)
{
// VHDR
case 0x56484452:
{
formatData.OneShotHiSamples = instrumentStream.Read_B_UINT32();
formatData.RepeatHiSamples = instrumentStream.Read_B_UINT32();
formatData.SamplesPerHiCycle = instrumentStream.Read_B_UINT32();
formatData.SamplesPerSec = instrumentStream.Read_B_UINT16();
formatData.Octaves = instrumentStream.Read_UINT8();

byte compressed = instrumentStream.Read_UINT8();
if (compressed != 0)
{
errorMessage = string.Format(Resources.IDS_SMUS_ERR_LOADING_READ_EXTERNAL_FILE, instrumentFileName);
return false;
}

formatData.Volume = instrumentStream.Read_B_UINT32();

formLength -= 20;
chunkLength -= 20;
break;
}

// BODY
case 0x424f4459:
{
if ((formatData.SampleData != null) || (formatData.Octaves == 0))
{
errorMessage = string.Format(Resources.IDS_SMUS_ERR_LOADING_READ_EXTERNAL_FILE, instrumentFileName);
return false;
}

formatData.SampleData = instrumentStream.ReadSampleData(instruments.Count, (int)chunkLength, out int readBytes);
if (readBytes != chunkLength)
{
errorMessage = string.Format(Resources.IDS_SMUS_ERR_LOADING_READ_EXTERNAL_FILE, instrumentFileName);
return false;
}

formLength -= chunkLength;
chunkLength = 0;
break;
}
}

if (chunkLength > 0)
{
instrumentStream.Seek(chunkLength, SeekOrigin.Current);
formLength -= chunkLength;
}
}
LoadResult result = IffSampleLoader.Load(instrumentStream, instruments.Count, out formatData);

if (formatData.SampleData == null)
if (result != LoadResult.Ok)
{
errorMessage = string.Format(Resources.IDS_SMUS_ERR_LOADING_READ_EXTERNAL_FILE, instrumentFileName);
return false;
Expand Down Expand Up @@ -156,7 +79,7 @@ public bool Load(ModuleStream instrumentStream, PlayerFileInfo fileInfo, string
break;
}

formatData.NumberOfHiOctavesToSkip = count;
numberOfHiOctavesToSkip = count;

return true;
}
Expand All @@ -183,7 +106,7 @@ public void Setup(GlobalInfo globalInfo, GlobalPlayingInfo playingInfo, VoiceInf
playInfo.Octave = (byte)octave;
playInfo.Note = (byte)note;

int octaveInFormat = (-(octave - 10)) - formatData.NumberOfHiOctavesToSkip;
int octaveInFormat = (-(octave - 10)) - numberOfHiOctavesToSkip;
if ((octaveInFormat < 0) || (octaveInFormat >= formatData.Octaves))
{
voice.InstrumentSetupSequence = InstrumentSetup.Nothing;
Expand Down Expand Up @@ -323,7 +246,7 @@ public SampleInfo GetSampleInfo(GlobalInfo globalInfo)
SampleInfo.MultiOctaveInfo[] multiOctaveInfo = new SampleInfo.MultiOctaveInfo[8];
List<sbyte[]> allSamples = new List<sbyte[]>();

for (int i = 0, j = formatData.NumberOfHiOctavesToSkip; (i < formatData.Octaves) && (j < 8); i++, j++)
for (int i = 0, j = numberOfHiOctavesToSkip; (i < formatData.Octaves) && (j < 8); i++, j++)
{
uint sampleLength = formatData.OneShotHiSamples + formatData.RepeatHiSamples;
uint startOffset = (sampleLength << i) - sampleLength;
Expand All @@ -345,11 +268,11 @@ public SampleInfo GetSampleInfo(GlobalInfo globalInfo)
allSamples.Add(formatData.SampleData.AsSpan((int)multiOctaveInfo[j].SampleOffset, (int)multiOctaveInfo[j].Length).ToArray());
}

for (int i = 0; i < formatData.NumberOfHiOctavesToSkip; i++)
multiOctaveInfo[i] = multiOctaveInfo[formatData.NumberOfHiOctavesToSkip];
for (int i = 0; i < numberOfHiOctavesToSkip; i++)
multiOctaveInfo[i] = multiOctaveInfo[numberOfHiOctavesToSkip];

for (int i = formatData.NumberOfHiOctavesToSkip + formatData.Octaves; i < 8; i++)
multiOctaveInfo[i] = multiOctaveInfo[formatData.NumberOfHiOctavesToSkip + formatData.Octaves - 1];
for (int i = numberOfHiOctavesToSkip + formatData.Octaves; i < 8; i++)
multiOctaveInfo[i] = multiOctaveInfo[numberOfHiOctavesToSkip + formatData.Octaves - 1];

sampleInfo.MultiOctaveSamples = multiOctaveInfo;
sampleInfo.MultiOctaveAllSamples = allSamples.ToArray();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
/* license of NostalgicPlayer is keep. See the LICENSE file for more */
/* information. */
/******************************************************************************/
namespace Polycode.NostalgicPlayer.Agent.Player.IffSmus.Instruments
namespace Polycode.NostalgicPlayer.Kit.Containers
{
/// <summary>
/// Holds data for IFF sample format
/// </summary>
internal class FormData
public class IffSample
{
// VHDR information
public uint OneShotHiSamples;
Expand All @@ -18,7 +18,6 @@ internal class FormData
public byte Octaves;
public uint Volume;

public ushort NumberOfHiOctavesToSkip;
public sbyte[] SampleData;
}
}
20 changes: 20 additions & 0 deletions Source/NostalgicPlayerKit/Containers/LoadResult.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/******************************************************************************/
/* This source, or parts thereof, may be used in any software as long the */
/* license of NostalgicPlayer is keep. See the LICENSE file for more */
/* information. */
/******************************************************************************/
namespace Polycode.NostalgicPlayer.Kit.Containers
{
/// <summary>
/// Result from sample loaders
/// </summary>
public enum LoadResult
{
/// <summary></summary>
Ok,
/// <summary></summary>
UnknownFormat,
/// <summary></summary>
Error
}
}
110 changes: 110 additions & 0 deletions Source/NostalgicPlayerKit/Utility/IffSampleLoader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
/******************************************************************************/
/* This source, or parts thereof, may be used in any software as long the */
/* license of NostalgicPlayer is keep. See the LICENSE file for more */
/* information. */
/******************************************************************************/
using System.IO;
using Polycode.NostalgicPlayer.Kit.Containers;
using Polycode.NostalgicPlayer.Kit.Streams;

namespace Polycode.NostalgicPlayer.Kit.Utility
{
/// <summary>
/// Helper class to load IFF samples
/// </summary>
public static class IffSampleLoader
{
/********************************************************************/
/// <summary>
/// Load an IFF sample and return the data
/// </summary>
/********************************************************************/
public static LoadResult Load(ModuleStream moduleStream, int sampleNumber, out IffSample iffSample)
{
iffSample = null;

if (moduleStream.Read_B_UINT32() != 0x464f524d) // FORM
{
// Seek back again
moduleStream.Seek(-4, SeekOrigin.Current);

return LoadResult.UnknownFormat;
}

uint formLength = moduleStream.Read_B_UINT32();

if (moduleStream.Read_B_UINT32() != 0x38535658) // 8SVX
{
// Seek back again
moduleStream.Seek(-8, SeekOrigin.Current);

return LoadResult.UnknownFormat;
}

formLength -= 4;

IffSample info = new IffSample();

while (formLength > 0)
{
uint chunkName = moduleStream.Read_B_UINT32();
uint chunkLength = moduleStream.Read_B_UINT32();
formLength -= 8;

if ((chunkLength % 2) != 0)
chunkLength++;

switch (chunkName)
{
// VHDR
case 0x56484452:
{
info.OneShotHiSamples = moduleStream.Read_B_UINT32();
info.RepeatHiSamples = moduleStream.Read_B_UINT32();
info.SamplesPerHiCycle = moduleStream.Read_B_UINT32();
info.SamplesPerSec = moduleStream.Read_B_UINT16();
info.Octaves = moduleStream.Read_UINT8();

byte compressed = moduleStream.Read_UINT8();
if (compressed != 0)
return LoadResult.Error;

info.Volume = moduleStream.Read_B_UINT32();

formLength -= 20;
chunkLength -= 20;
break;
}

// BODY
case 0x424f4459:
{
if ((info.SampleData != null) || (info.Octaves == 0))
return LoadResult.Error;

info.SampleData = moduleStream.ReadSampleData(sampleNumber, (int)chunkLength, out int readBytes);
if (readBytes != chunkLength)
return LoadResult.Error;

formLength -= chunkLength;
chunkLength = 0;
break;
}
}

if (chunkLength > 0)
{
moduleStream.Seek(chunkLength, SeekOrigin.Current);
formLength -= chunkLength;
}
}

if (info.SampleData == null)
return LoadResult.Error;

iffSample = info;

return LoadResult.Ok;
}
}
}

0 comments on commit 1dd1eab

Please sign in to comment.