Skip to content

Commit

Permalink
The mixer now uses interleaved stereo samples instead of a separate b…
Browse files Browse the repository at this point in the history
…uffer for each channel.
  • Loading branch information
neumatho committed Jun 24, 2024
1 parent ecb8ac0 commit e23573c
Show file tree
Hide file tree
Showing 19 changed files with 202 additions and 472 deletions.
32 changes: 12 additions & 20 deletions Source/Agents/Players/OctaMed/Implementation/Mixer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ protected enum PlayFlag
PingPongLoop = 0x04
}

private static readonly ushort[] bpmCompVals = { 195, 97, 65, 49, 39, 32, 28, 24, 22, 20 };
private static readonly ushort[] bpmCompVals = [ 195, 97, 65, 49, 39, 32, 28, 24, 22, 20 ];

protected readonly OctaMedWorker worker;

Expand Down Expand Up @@ -209,37 +209,29 @@ protected void Play(uint chNum, NoteNum note, InstNum instNum, Sample smp, uint
if (startOffs >= smp.GetLength())
startOffs = 0;

sbyte[] leftAdr = smp.GetPlayBuffer(0, note, ref loopStart, ref loopLen);
if (leftAdr != null)
sbyte[] sampAdr = smp.GetPlayBuffer(note, ref loopStart, ref loopLen);
if (sampAdr != null)
{
PlaySampleFlag playSampleFlag = PlaySampleFlag.None;
uint len = (uint)leftAdr.Length;
uint len = (uint)sampAdr.Length;

if (smp.Is16Bit())
{
playSampleFlag |= PlaySampleFlag._16Bit;
len /= 2;
}

if ((flags & PlayFlag.Backwards) != 0)
playSampleFlag |= PlaySampleFlag.Backwards;

if (smp.IsStereo())
{
uint d1 = 0, d2 = 0;

sbyte[] rightAdr = smp.GetPlayBuffer(1, note, ref d1, ref d2);
if (rightAdr != null)
{
// Okay, tell NostalgicPlayer to play the sample
worker.VirtualChannels[chNum].PlayStereoSample((short)instNum, leftAdr, rightAdr, startOffs, len, playSampleFlag);
}
}
else
{
// Okay, tell NostalgicPlayer to play the sample
worker.VirtualChannels[chNum].PlaySample((short)instNum, leftAdr, startOffs, len, playSampleFlag);
playSampleFlag |= PlaySampleFlag.Stereo;
len /= 2;
}

if ((flags & PlayFlag.Backwards) != 0)
playSampleFlag |= PlaySampleFlag.Backwards;

// Okay, tell NostalgicPlayer to play the sample
worker.VirtualChannels[chNum].PlaySample((short)instNum, sampAdr, startOffs, len, playSampleFlag);
}

// Set loop
Expand Down
30 changes: 18 additions & 12 deletions Source/Agents/Players/OctaMed/Implementation/MmdSampleHdr.cs
Original file line number Diff line number Diff line change
Expand Up @@ -136,52 +136,58 @@ public void ReadSampleData(ModuleStream moduleStream, Sample dest)
{
using (ModuleStream sampleDataStream = moduleStream.GetSampleDataStream((int)sampleNumber, (int)numBytes))
{
for (ushort chCnt = 0; chCnt < (stereo ? 2 : 1); chCnt++)
int channels = (stereo ? 2 : 1);

for (ushort chCnt = 0; chCnt < channels; chCnt++)
{
for (int oct = 0; ; oct++)
{
sbyte[] buf = dest.GetSampleBuffer(chCnt, oct);
sbyte[] buf = dest.GetSampleBuffer(oct);
if (buf == null)
break;

int length = buf.Length;
if (dest.IsStereo())
length /= 2;

if (sixtBit)
{
Span<short> buf16 = MemoryMarshal.Cast<sbyte, short>(buf);

if ((type & InstrDeltaCode) != 0)
{
short prev = sampleDataStream.Read_B_INT16();
buf16[0] = prev;
buf16[chCnt] = prev;

for (int cnt2 = 1; cnt2 < buf16.Length; cnt2++)
for (int cnt2 = 1; cnt2 < length; cnt2++)
{
prev += sampleDataStream.Read_B_INT16();
buf16[cnt2] = prev;
buf16[cnt2 * channels + chCnt] = prev;
}
}
else
{
for (int cnt2 = 0; cnt2 < buf16.Length; cnt2++)
buf16[cnt2] = sampleDataStream.Read_B_INT16();
for (int cnt2 = 0; cnt2 < length; cnt2++)
buf16[cnt2 * channels + chCnt] = sampleDataStream.Read_B_INT16();
}
}
else
{
if ((type & InstrDeltaCode) != 0)
{
sbyte prev = sampleDataStream.Read_INT8();
buf[0] = prev;
buf[chCnt] = prev;

for (int cnt2 = 1; cnt2 < buf.Length; cnt2++)
for (int cnt2 = 1; cnt2 < length; cnt2++)
{
prev += sampleDataStream.Read_INT8();
buf[cnt2] = prev;
buf[cnt2 * channels + chCnt] = prev;
}
}
else
{
for (int cnt2 = 0; cnt2 < buf.Length; cnt2++)
buf[cnt2] = sampleDataStream.Read_INT8();
for (int cnt2 = 0; cnt2 < length; cnt2++)
buf[cnt2 * channels + chCnt] = sampleDataStream.Read_INT8();
}
}
}
Expand Down
44 changes: 22 additions & 22 deletions Source/Agents/Players/OctaMed/Implementation/Sample.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,11 @@ internal class Sample

private readonly OctaMedWorker worker;

private readonly sbyte[][][] data = new sbyte[2][][];
private sbyte[][] data;
private uint dataLen; // Length of one sample
private uint length; // Sample length in samples
private bool isStereo;
private bool is16Bit;
private ushort channels; // 1 = Mono, 2 = Stereo
private int sampleType;
private int numberOfOctaves; // Holds the number of octaves the sample contains

Expand All @@ -54,7 +53,6 @@ public Sample(OctaMedWorker worker)
this.worker = worker;

dataLen = sizeof(sbyte);
channels = 1;
}


Expand Down Expand Up @@ -91,15 +89,15 @@ public uint GetLength()
/// Return the buffer to the sample data
/// </summary>
/********************************************************************/
public sbyte[] GetSampleBuffer(ushort ch, int octave)
public sbyte[] GetSampleBuffer(int octave)
{
if (octave >= numberOfOctaves)
return null;

if (data[ch] == null)
if (data == null)
return null;

return data[ch][octave];
return data[octave];
}


Expand All @@ -109,10 +107,10 @@ public sbyte[] GetSampleBuffer(ushort ch, int octave)
/// Return the buffer to play
/// </summary>
/********************************************************************/
public sbyte[] GetPlayBuffer(ushort ch, NoteNum note, ref uint repeat, ref uint repLen)
public sbyte[] GetPlayBuffer(NoteNum note, ref uint repeat, ref uint repLen)
{
if (sampleType == 0)
return data[ch][0];
return data[0];

int octave = note / 12;
if (octave > 5)
Expand All @@ -122,7 +120,7 @@ public sbyte[] GetPlayBuffer(ushort ch, NoteNum note, ref uint repeat, ref uint
repeat <<= bufNum;
repLen <<= bufNum;

return data[ch][bufNum];
return data[bufNum];
}


Expand Down Expand Up @@ -222,13 +220,11 @@ private void SetStereo(bool stereo)
{
// No conversion implemented
isStereo = true;
channels = 2;
}
else
{
// We don't mix the stereo sample together to a mono sample
isStereo = false;
channels = 1;
}
}

Expand Down Expand Up @@ -265,8 +261,7 @@ private void SetMultiOctave(short type)
sampleType = type > 6 ? 0 : (type & 0x0f);
numberOfOctaves = multiOctaveCount[sampleType];

for (ushort chCnt = 0; chCnt < channels; chCnt++)
data[chCnt] = new sbyte[numberOfOctaves][];
data = new sbyte[numberOfOctaves][];
}


Expand All @@ -278,11 +273,8 @@ private void SetMultiOctave(short type)
/********************************************************************/
private void SetLength(uint newLen)
{
for (ushort chCnt = 0; chCnt < channels; chCnt++)
{
if (newLen != length)
InitSampleBuffers(chCnt, dataLen * newLen);
}
if (newLen != length)
InitSampleBuffers(dataLen * newLen);

length = newLen;

Expand Down Expand Up @@ -310,21 +302,29 @@ private void ValidateLoop()
/// Set sample buffers
/// </summary>
/********************************************************************/
private void InitSampleBuffers(ushort ch, uint len)
private void InitSampleBuffers(uint len)
{
if (len == 0)
data[ch] = null;
data = null;
else
{
if (numberOfOctaves == 1)
data[ch][0] = new sbyte[len];
{
if (isStereo)
len *= 2;

data[0] = new sbyte[len];
}
else
{
uint baseLen = len / (uint)((1 << numberOfOctaves) - 1);

if (isStereo)
baseLen *= 2;

for (int i = 0; i < numberOfOctaves; i++)
{
data[ch][i] = new sbyte[baseLen];
data[i] = new sbyte[baseLen];
baseLen <<= 1;
}
}
Expand Down
2 changes: 1 addition & 1 deletion Source/Agents/Players/OctaMed/OctaMed.cs
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ public IdentifyFormatInfo IdentifyFormat(PlayerFileInfo fileInfo)
if (moduleType == ModuleType.Unknown)
return null;

return new IdentifyFormatInfo(new OctaMedWorker(moduleType), moduleTypeLookup[moduleType]);
return new IdentifyFormatInfo(new OctaMedWorker(), moduleTypeLookup[moduleType]);
}
#endregion
}
Expand Down
39 changes: 7 additions & 32 deletions Source/Agents/Players/OctaMed/OctaMedWorker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ namespace Polycode.NostalgicPlayer.Agent.Player.OctaMed
/// </summary>
internal class OctaMedWorker : ModulePlayerWithSubSongDurationAgentBase
{
private readonly ModuleType currentModuleType;

private uint numSamples;
private ushort numChannels;

Expand All @@ -34,16 +32,6 @@ internal class OctaMedWorker : ModulePlayerWithSubSongDurationAgentBase
private const int InfoSpeedLine = 5;
private const int InfoTempoLine = 6;

/********************************************************************/
/// <summary>
/// Constructor
/// </summary>
/********************************************************************/
public OctaMedWorker(ModuleType moduleType = ModuleType.Unknown)
{
currentModuleType = moduleType;
}

#region IPlayerAgent implementation
/********************************************************************/
/// <summary>
Expand Down Expand Up @@ -1385,47 +1373,34 @@ public override IEnumerable<SampleInfo> Samples
uint repLen = sampleInfo.LoopLength;
NoteNum note = (NoteNum)(oct * 12);

sampleInfo.MultiOctaveSamples[oct + 1].Sample = new sbyte[2][];

sampleInfo.MultiOctaveSamples[oct + 1].Sample[0] = sample.GetPlayBuffer(0, note, ref repeat, ref repLen);
sampleInfo.MultiOctaveSamples[oct + 1].Sample = sample.GetPlayBuffer(note, ref repeat, ref repLen);
sampleInfo.MultiOctaveSamples[oct + 1].LoopStart = repeat;
sampleInfo.MultiOctaveSamples[oct + 1].LoopLength = repLen;
sampleInfo.MultiOctaveSamples[oct + 1].NoteAdd = sample.GetNoteDifference(note);

if (sample.IsStereo())
sampleInfo.MultiOctaveSamples[oct + 1].Sample[1] = sample.GetPlayBuffer(1, note, ref repeat, ref repLen);
}

// OctaMed only have 6 octaves, so the first and last will use the same buffer
sampleInfo.MultiOctaveSamples[0] = sampleInfo.MultiOctaveSamples[1];
sampleInfo.MultiOctaveSamples[7] = sampleInfo.MultiOctaveSamples[6];

// Remember all samples
sampleInfo.MultiOctaveAllSamples = new sbyte[2][][];

List<(sbyte[] left, sbyte[] right)> samples = new List<(sbyte[] left, sbyte[] right)>();
List<sbyte[]> samples = new List<sbyte[]>();
oct = 0;

sbyte[] leftBuf;
while ((leftBuf = sample.GetSampleBuffer(0, oct)) != null)
sbyte[] sampBuf;
while ((sampBuf = sample.GetSampleBuffer(oct)) != null)
{
sbyte[] rightBuf = sample.GetSampleBuffer(1, oct);
samples.Add((leftBuf, rightBuf));
samples.Add(sampBuf);

oct++;
}

sampleInfo.MultiOctaveAllSamples[0] = samples.Select(s => s.left).ToArray();
if (sample.IsStereo())
sampleInfo.MultiOctaveAllSamples[1] = samples.Select(s => s.right).ToArray();
sampleInfo.MultiOctaveAllSamples = samples.ToArray();

sampleInfo.Flags |= SampleInfo.SampleFlag.MultiOctave;
}
else
{
sampleInfo.Sample = sample.GetSampleBuffer(0, 0);
sampleInfo.SecondSample = sample.GetSampleBuffer(1, 0);
}
sampleInfo.Sample = sample.GetSampleBuffer(0);

// Find out the type of the sample
if (sample.IsSynthSound())
Expand Down
12 changes: 5 additions & 7 deletions Source/Clients/NostalgicPlayer/MainWindow/MainWindowForm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -819,7 +819,6 @@ public bool PlayChannels(IChannel[] channels)
if (((sampleInfo.Sample != null) || (sampleInfo.MultiOctaveSamples != null)) && (sampleInfo.Length > 0))
{
Array sample = sampleInfo.Sample;
Array secondSample = sampleInfo.SecondSample;
uint offset = sampleInfo.SampleOffset;
uint length = sampleInfo.Length;
uint loopStart = sampleInfo.LoopStart;
Expand All @@ -837,8 +836,7 @@ public bool PlayChannels(IChannel[] channels)
SampleInfo.MultiOctaveInfo octaveInfo = sampleInfo.MultiOctaveSamples[octave];
note += octaveInfo.NoteAdd;

sample = octaveInfo.Sample[0];
secondSample = octaveInfo.Sample.Length > 1 ? octaveInfo.Sample[1] : null;
sample = octaveInfo.Sample;

length = (uint)sample.Length;
loopStart = octaveInfo.LoopStart;
Expand All @@ -865,11 +863,11 @@ public bool PlayChannels(IChannel[] channels)
if ((sampleInfo.Flags & SampleInfo.SampleFlag._16Bit) != 0)
playFlag |= PlaySampleFlag._16Bit;

// Play it
if ((sampleInfo.Flags & SampleInfo.SampleFlag.Stereo) != 0)
channel.PlayStereoSample(-1, sample, secondSample, offset, length, playFlag);
else
channel.PlaySample(-1, sample, offset, length, playFlag);
playFlag |= PlaySampleFlag.Stereo;

// Play it
channel.PlaySample(-1, sample, offset, length, playFlag);

channel.SetFrequency((uint)frequency);

Expand Down
Loading

0 comments on commit e23573c

Please sign in to comment.