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());
}
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;
}
}
}