LNXSDK/Kha/Sources/kha/audio2/ResamplingAudioChannel.hx
2025-01-22 16:18:30 +01:00

138 lines
3.4 KiB
Haxe

package kha.audio2;
import kha.arrays.Float32Array;
class ResamplingAudioChannel extends AudioChannel {
public var sampleRate: Int;
public function new(looping: Bool, sampleRate: Int) {
super(looping);
this.sampleRate = sampleRate;
}
public override function nextSamples(requestedSamples: Float32Array, requestedLength: Int, sampleRate: Int): Void {
if (paused || stopped) {
for (i in 0...requestedLength) {
requestedSamples[i] = 0;
}
return;
}
var requestedSamplesIndex = 0;
while (requestedSamplesIndex < requestedLength) {
for (i in 0...min(sampleLength(sampleRate) - myPosition, requestedLength - requestedSamplesIndex)) {
requestedSamples[requestedSamplesIndex++] = sample(myPosition++, sampleRate);
}
if (myPosition >= sampleLength(sampleRate)) {
myPosition = 0;
if (!looping) {
stopped = true;
break;
}
}
}
while (requestedSamplesIndex < requestedLength) {
requestedSamples[requestedSamplesIndex++] = 0;
}
}
inline function sample(position: Int, sampleRate: Int): Float {
var even = position % 2 == 0;
var factor = this.sampleRate / sampleRate;
if (even) {
position = Std.int(position / 2);
var pos = factor * position;
var pos1 = Math.floor(pos);
var pos2 = Math.floor(pos + 1);
pos1 *= 2;
pos2 *= 2;
var minimum = 0;
var maximum = data.length - 1;
maximum = maximum % 2 == 0 ? maximum : maximum - 1;
var a = (pos1 < minimum || pos1 > maximum) ? 0 : data[pos1];
var b = (pos2 < minimum || pos2 > maximum) ? 0 : data[pos2];
return lerp(a, b, pos - Math.floor(pos));
}
else {
position = Std.int(position / 2);
var pos = factor * position;
var pos1 = Math.floor(pos);
var pos2 = Math.floor(pos + 1);
pos1 = pos1 * 2 + 1;
pos2 = pos2 * 2 + 1;
var minimum = 1;
var maximum = data.length - 1;
maximum = maximum % 2 != 0 ? maximum : maximum - 1;
var a = (pos1 < minimum || pos1 > maximum) ? 0 : data[pos1];
var b = (pos2 < minimum || pos2 > maximum) ? 0 : data[pos2];
return lerp(a, b, pos - Math.floor(pos));
}
}
inline function lerp(v0: Float, v1: Float, t: Float) {
return (1 - t) * v0 + t * v1;
}
inline function sampleLength(sampleRate: Int): Int {
var value = Math.ceil(data.length * (sampleRate / this.sampleRate));
return value % 2 == 0 ? value : value + 1;
}
public override function play(): Void {
paused = false;
stopped = false;
kha.audio1.Audio._playAgain(this);
}
public override function pause(): Void {
paused = true;
}
public override function stop(): Void {
myPosition = 0;
stopped = true;
}
override function get_length(): Float {
return data.length / this.sampleRate / 2; // 44.1 khz in stereo
}
override function get_position(): Float {
return myPosition / kha.audio2.Audio.samplesPerSecond / 2;
}
override function set_position(value: Float): Float {
var pos = Math.round(value * kha.audio2.Audio.samplesPerSecond * 2.0);
pos = pos % 2 == 0 ? pos : pos + 1;
myPosition = max(min(pos, sampleLength(kha.audio2.Audio.samplesPerSecond)), 0);
return value;
}
override function get_volume(): Float {
return myVolume;
}
override function set_volume(value: Float): Float {
return myVolume = value;
}
override function get_finished(): Bool {
return stopped;
}
static inline function max(a: Int, b: Int) {
return a > b ? a : b;
}
static inline function min(a: Int, b: Int) {
return a < b ? a : b;
}
}