UNPKG

spessasynth_core

Version:

MIDI and SoundFont2/DLS library with no compromises

77 lines (75 loc) 3.13 kB
import { IndexedByteArray } from "../../../utils/indexed_array.js"; import { writeStringAsBytes } from "../../../utils/byte_functions/string.js"; import { writeDword, writeWord } from "../../../utils/byte_functions/little_endian.js"; import { writeRIFFChunkRaw } from "../riff_chunk.js"; import { SF3_BIT_FLIT } from "../../read_sf2/samples.js"; /** * @this {BasicSoundBank} * @param smplStartOffsets {number[]} * @param smplEndOffsets {number[]} * @returns {ReturnedExtendedSf2Chunks} */ export function getSHDR(smplStartOffsets, smplEndOffsets) { const sampleLength = 46; const shdrSize = sampleLength * (this.samples.length + 1); // +1 because EOP const shdrData = new IndexedByteArray(shdrSize); // https://github.com/spessasus/soundfont-proposals/blob/main/extended_limits.md const xshdrData = new IndexedByteArray(shdrSize); let maxSampleLink = 0; this.samples.forEach((sample, index) => { // sample name writeStringAsBytes(shdrData, sample.sampleName.substring(0, 20), 20); writeStringAsBytes(xshdrData, sample.sampleName.substring(20), 20); // start offset const dwStart = smplStartOffsets[index]; writeDword(shdrData, dwStart); xshdrData.currentIndex += 4; // end offset const dwEnd = smplEndOffsets[index]; writeDword(shdrData, dwEnd); xshdrData.currentIndex += 4; // loop is stored as relative in sample points, change it to absolute sample points here let loopStart = sample.sampleLoopStartIndex + dwStart; let loopEnd = sample.sampleLoopEndIndex + dwStart; if (sample.isCompressed) { // https://github.com/FluidSynth/fluidsynth/wiki/SoundFont3Format loopStart -= dwStart; loopEnd -= dwStart; } writeDword(shdrData, loopStart); writeDword(shdrData, loopEnd); // sample rate writeDword(shdrData, sample.sampleRate); // pitch and correction shdrData[shdrData.currentIndex++] = sample.samplePitch; shdrData[shdrData.currentIndex++] = sample.samplePitchCorrection; // skip all those for xshdr xshdrData.currentIndex += 14; // sample link const sampleLinkIndex = this.samples.indexOf(sample.linkedSample); writeWord(shdrData, Math.max(0, sampleLinkIndex) & 0xFFFF); writeWord(xshdrData, Math.max(0, sampleLinkIndex) >> 16); maxSampleLink = Math.max(maxSampleLink, sampleLinkIndex); // sample type: add byte if compressed let type = sample.sampleType; if (sample.isCompressed) { type |= SF3_BIT_FLIT; } writeWord(shdrData, type); xshdrData.currentIndex += 2; }); // write EOS and zero everything else writeStringAsBytes(shdrData, "EOS", sampleLength); writeStringAsBytes(xshdrData, "EOS", sampleLength); const shdr = writeRIFFChunkRaw("shdr", shdrData); const xshdr = writeRIFFChunkRaw("shdr", xshdrData); return { pdta: shdr, xdta: xshdr, highestIndex: maxSampleLink }; }