user3441364 user3441364 - 14 days ago 5
C# Question

How do I read the SMPL chunk of a WAV file with C#?

I need to read the

dwStart
and
dwEnd
properties within the SMPL chunk because those points should specify the startpoint and endpoint of the loop in sample.
I'm converting my Directwave libraries to Bitwig’s .multisample format so my app doesn't need to play the WAV file. It just needs to read the loop points so it can be added to an XML that looks like this:

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<multisample name="Test Bell">
<generator>Bitwig Studio</generator>
<category>Bell</category>
<creator>John</creator>
<description>Misc</description>
<layer name="Default">
<sample file="Bell_004 - C3.wav" gain="0.00" sample-start="0.000" sample-stop="88048.000">
<key track="true" tune="0.00">
<velocity />
<loop mode="sustain" start="58709.000" stop="88048.000" />
</key>
</sample>
</layer>
</multisample>


UPDATE:
Mark Heath's code works to find the smpl chunk and loop points in Kontakt WAVs but it doesn't find the an smpl chunk in the WAV files created by DirectWave For example this file:
http://stash.reaper.fm/28963/Flute_006_C3.wav

I used the code below and it only found an inst chunk. How can I find the start and end loop points if there is no smpl chunk?

var smp = reader.ExtraChunks.Where(ec => ec.IdentifierAsString != null);
foreach (var x in smp)
{
MessageBox.Show(x.IdentifierAsString.ToString());
}

Answer

You can use NAudio WaveFileReader to explore extra chunks. Here's some code for the "smpl" chunk:

var wavFilePath = @"E:\Recording\sfz\Equinox Steinway D\SteinwayDmA#0.wav";
using (var reader = new WaveFileReader(wavFilePath))
{
    var smp = reader.ExtraChunks.FirstOrDefault(ec => ec.IdentifierAsString == "smpl");
    if (smp != null)
    {
        var chunkData = reader.GetChunkData(smp);
        // https://sites.google.com/site/musicgapi/technical-documents/wav-file-format#smpl
        var midiNote = BitConverter.ToInt32(chunkData,12);
        var numberOfSamples = BitConverter.ToInt32(chunkData,28);
        Console.WriteLine($"MIDI {midiNote}, {numberOfSamples} samples");
        int offset = 36;
        for (int n = 0; n < numberOfSamples; n++)
        {
            var cuePointId = BitConverter.ToInt32(chunkData,offset);
            var type = BitConverter.ToInt32(chunkData, offset + 4); // 0 = loop forward, 1 = alternating loop, 2 = reverse

            var start = BitConverter.ToInt32(chunkData, offset + 8);
            var end = BitConverter.ToInt32(chunkData, offset + 12);
            var fraction = BitConverter.ToInt32(chunkData, offset + 16);
            var playCount = BitConverter.ToInt32(chunkData, offset + 20);
            Console.WriteLine($"Sample {cuePointId} Start {start} End {end}");
            offset+= 24;
        }
    }
}