forked from LeenkxTeam/LNXSDK
Update Files
This commit is contained in:
21
lib/aura/Sources/aura/format/InputExtension.hx
Normal file
21
lib/aura/Sources/aura/format/InputExtension.hx
Normal file
@ -0,0 +1,21 @@
|
||||
package aura.format;
|
||||
|
||||
import haxe.Int64;
|
||||
import haxe.io.Input;
|
||||
|
||||
inline function readInt64(inp: Input): Int64 {
|
||||
final first = inp.readInt32();
|
||||
final second = inp.readInt32();
|
||||
|
||||
return inp.bigEndian ? Int64.make(first, second) : Int64.make(second, first);
|
||||
}
|
||||
|
||||
inline function readUInt32(inp: Input): Int64 {
|
||||
var out: Int64 = 0;
|
||||
|
||||
for (i in 0...4) {
|
||||
out += Int64.shl(inp.readByte(), (inp.bigEndian ? 3 - i : i) * 8);
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
170
lib/aura/Sources/aura/format/mhr/MHRReader.hx
Normal file
170
lib/aura/Sources/aura/format/mhr/MHRReader.hx
Normal file
@ -0,0 +1,170 @@
|
||||
/**
|
||||
Specification:
|
||||
V1: https://github.com/kcat/openal-soft/blob/be7938ed385e18c7800c663672262bb2976aa734/docs/hrtf.txt
|
||||
V2: https://github.com/kcat/openal-soft/blob/0349bcc500fdb9b1245a5ddce01b2896bcf9bbb9/docs/hrtf.txt
|
||||
V3: https://github.com/kcat/openal-soft/blob/3ef4bffaf959d06527a247faa19cc869781745e4/docs/hrtf.txt
|
||||
**/
|
||||
|
||||
package aura.format.mhr;
|
||||
|
||||
import haxe.Int64;
|
||||
import haxe.ds.Vector;
|
||||
import haxe.io.Bytes;
|
||||
import haxe.io.BytesInput;
|
||||
|
||||
import kha.arrays.Float32Array;
|
||||
|
||||
import aura.types.HRTF;
|
||||
|
||||
using aura.format.InputExtension;
|
||||
|
||||
/**
|
||||
Load MHR HRTF files (format versions 1–3 are supported) into `HRTF` objects.
|
||||
**/
|
||||
class MHRReader {
|
||||
|
||||
public static function read(bytes: Bytes): HRTF {
|
||||
final inp = new BytesInput(bytes);
|
||||
inp.bigEndian = false;
|
||||
|
||||
final magic = inp.readString(8, UTF8);
|
||||
final version = versionFromMagic(magic);
|
||||
|
||||
final sampleRate = Int64.toInt(inp.readUInt32());
|
||||
final sampleType = switch (version) {
|
||||
case V1: SampleType16Bit;
|
||||
case V2: inp.readByte();
|
||||
case V3: SampleType24Bit;
|
||||
}
|
||||
|
||||
final channelType = switch (version) {
|
||||
case V1: 0; // mono
|
||||
case V2 | V3: inp.readByte();
|
||||
}
|
||||
final channels = channelType + 1;
|
||||
|
||||
// Samples per HRIR (head related impulse response) per channel
|
||||
final hrirSize = inp.readByte();
|
||||
|
||||
// Number of fields used by the data set. Each field represents a
|
||||
// set of points for a given distance.
|
||||
final fieldCount = version == V1 ? 1 : inp.readByte();
|
||||
|
||||
final fields = new Vector<Field>(fieldCount);
|
||||
var totalHRIRCount = 0;
|
||||
for (i in 0...fieldCount) {
|
||||
final field = new Field();
|
||||
|
||||
// 1000mm is arbitrary, but it doesn't matter since the interpolation
|
||||
// can only access one distance anyway...
|
||||
field.distance = version == V1 ? 1000 : inp.readUInt16();
|
||||
field.evCount = inp.readByte();
|
||||
field.azCount = new Vector<Int>(field.evCount);
|
||||
field.evHRIROffsets = new Vector<Int>(field.evCount);
|
||||
|
||||
var fieldHrirCount = 0;
|
||||
for (j in 0...field.evCount) {
|
||||
// Calculate the offset into the HRIR arrays. Different
|
||||
// elevations may have different amounts of azimuths/HRIRs
|
||||
field.evHRIROffsets[j] = fieldHrirCount;
|
||||
|
||||
field.azCount[j] = inp.readByte();
|
||||
fieldHrirCount += field.azCount[j];
|
||||
}
|
||||
field.hrirCount = fieldHrirCount;
|
||||
totalHRIRCount += fieldHrirCount;
|
||||
|
||||
fields[i] = field;
|
||||
}
|
||||
|
||||
// Read actual HRIR samples into coeffs
|
||||
for (i in 0...fieldCount) {
|
||||
final field = fields[i];
|
||||
final hrirs = new Vector<HRIR>(field.hrirCount);
|
||||
field.hrirs = hrirs;
|
||||
|
||||
for (j in 0...field.hrirCount) {
|
||||
// Create individual HRIR
|
||||
final hrir = hrirs[j] = new HRIR();
|
||||
|
||||
hrir.coeffs = new Float32Array(hrirSize * channels);
|
||||
switch (sampleType) {
|
||||
case SampleType16Bit:
|
||||
for (s in 0...hrirSize) {
|
||||
final coeff = inp.readInt16();
|
||||
// 32768 = 2^15
|
||||
hrir.coeffs[s] = coeff / (coeff < 0 ? 32768.0 : 32767.0);
|
||||
}
|
||||
|
||||
case SampleType24Bit:
|
||||
for (s in 0...hrirSize) {
|
||||
final coeff = inp.readInt24();
|
||||
// 8388608 = 2^23
|
||||
hrir.coeffs[s] = coeff / (coeff < 0 ? 8388608.0 : 8388607.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Read per-HRIR delay
|
||||
var maxDelayLength = 0.0;
|
||||
for (i in 0...fieldCount) {
|
||||
final field = fields[i];
|
||||
|
||||
for (j in 0...field.hrirCount) {
|
||||
final hrir = field.hrirs[j];
|
||||
|
||||
hrir.delays = new Vector<Float>(channels);
|
||||
for (ch in 0...channels) {
|
||||
// 6.2 fixed point
|
||||
final delayRaw = inp.readByte();
|
||||
final delayIntPart = delayRaw >> 2;
|
||||
final delayFloatPart = isBitSet(delayRaw, 1) * 0.5 + isBitSet(delayRaw, 0) * 0.25;
|
||||
final delay = delayIntPart + delayFloatPart;
|
||||
hrir.delays[ch] = delay;
|
||||
if (delay > maxDelayLength) {
|
||||
maxDelayLength = delay;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This should error if uncommented, check if we have reached the end of
|
||||
// the file.
|
||||
// inp.readByte();
|
||||
|
||||
return {
|
||||
sampleRate: sampleRate,
|
||||
numChannels: channels,
|
||||
hrirSize: hrirSize,
|
||||
hrirCount: totalHRIRCount,
|
||||
fields: fields,
|
||||
maxDelayLength: maxDelayLength
|
||||
};
|
||||
}
|
||||
|
||||
static inline function isBitSet(byte: Int, position: Int): Int {
|
||||
return (byte & (1 << position) == 0) ? 0 : 1;
|
||||
}
|
||||
|
||||
static inline function versionFromMagic(magic: String): MHRVersion {
|
||||
return switch (magic) {
|
||||
case "MinPHR01": V1;
|
||||
case "MinPHR02": V2;
|
||||
case "MinPHR03": V3;
|
||||
default:
|
||||
throw 'File is not an MHR HRTF file! Unknown magic string "$magic".';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private enum abstract SampleType(Int) from Int {
|
||||
var SampleType16Bit;
|
||||
var SampleType24Bit;
|
||||
}
|
||||
|
||||
private enum abstract MHRVersion(Int) {
|
||||
var V1;
|
||||
var V2;
|
||||
var V3;
|
||||
}
|
Reference in New Issue
Block a user