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