forked from LeenkxTeam/LNXSDK
Update Files
This commit is contained in:
107
Kha/Backends/HTML5/kha/audio2/Audio.hx
Normal file
107
Kha/Backends/HTML5/kha/audio2/Audio.hx
Normal file
@ -0,0 +1,107 @@
|
||||
package kha.audio2;
|
||||
|
||||
import js.Syntax;
|
||||
import js.Browser;
|
||||
import js.html.URL;
|
||||
import js.html.audio.AudioContext;
|
||||
import js.html.audio.AudioProcessingEvent;
|
||||
import js.html.audio.ScriptProcessorNode;
|
||||
import kha.internal.IntBox;
|
||||
import kha.js.AEAudioChannel;
|
||||
import kha.Sound;
|
||||
|
||||
class Audio {
|
||||
public static var disableGcInteractions = false;
|
||||
static var intBox: IntBox = new IntBox(0);
|
||||
static var buffer: Buffer;
|
||||
@:noCompletion public static var _context: AudioContext;
|
||||
static var processingNode: ScriptProcessorNode;
|
||||
|
||||
static function initContext(): Void {
|
||||
try {
|
||||
_context = new AudioContext();
|
||||
return;
|
||||
}
|
||||
catch (e:Dynamic) {}
|
||||
try {
|
||||
Syntax.code("this._context = new webkitAudioContext();");
|
||||
return;
|
||||
}
|
||||
catch (e:Dynamic) {}
|
||||
}
|
||||
|
||||
@:noCompletion
|
||||
public static function _init(): Bool {
|
||||
initContext();
|
||||
if (_context == null)
|
||||
return false;
|
||||
|
||||
Audio.samplesPerSecond = Math.round(_context.sampleRate);
|
||||
var bufferSize = 1024 * 2;
|
||||
buffer = new Buffer(bufferSize * 4, 2, Std.int(_context.sampleRate));
|
||||
|
||||
processingNode = _context.createScriptProcessor(bufferSize, 0, 2);
|
||||
processingNode.onaudioprocess = function(e: AudioProcessingEvent) {
|
||||
var output1 = e.outputBuffer.getChannelData(0);
|
||||
var output2 = e.outputBuffer.getChannelData(1);
|
||||
if (audioCallback != null) {
|
||||
intBox.value = e.outputBuffer.length * 2;
|
||||
audioCallback(intBox, buffer);
|
||||
for (i in 0...e.outputBuffer.length) {
|
||||
output1[i] = buffer.data.get(buffer.readLocation);
|
||||
buffer.readLocation += 1;
|
||||
output2[i] = buffer.data.get(buffer.readLocation);
|
||||
buffer.readLocation += 1;
|
||||
if (buffer.readLocation >= buffer.size) {
|
||||
buffer.readLocation = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (i in 0...e.outputBuffer.length) {
|
||||
output1[i] = 0;
|
||||
output2[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
processingNode.connect(_context.destination);
|
||||
return true;
|
||||
}
|
||||
|
||||
public static var samplesPerSecond: Int;
|
||||
|
||||
public static var audioCallback: kha.internal.IntBox->Buffer->Void;
|
||||
|
||||
static var virtualChannels: Array<VirtualStreamChannel> = [];
|
||||
|
||||
public static function wakeChannels() {
|
||||
SystemImpl.mobileAudioPlaying = true;
|
||||
for (channel in virtualChannels) {
|
||||
channel.wake();
|
||||
}
|
||||
}
|
||||
|
||||
public static function stream(sound: Sound, loop: Bool = false): kha.audio1.AudioChannel {
|
||||
// var source = _context.createMediaStreamSource(cast sound.compressedData.getData());
|
||||
// source.connect(_context.destination);
|
||||
var element = Browser.document.createAudioElement();
|
||||
#if kha_debug_html5
|
||||
var blob = new js.html.Blob([sound.compressedData.getData()], {type: "audio/ogg"});
|
||||
#else
|
||||
var blob = new js.html.Blob([sound.compressedData.getData()], {type: "audio/mp4"});
|
||||
#end
|
||||
element.src = URL.createObjectURL(blob);
|
||||
element.loop = loop;
|
||||
var channel = new AEAudioChannel(element, loop);
|
||||
|
||||
if (SystemImpl.mobileAudioPlaying) {
|
||||
channel.play();
|
||||
return channel;
|
||||
}
|
||||
else {
|
||||
var virtualChannel = new VirtualStreamChannel(channel, loop);
|
||||
virtualChannels.push(virtualChannel);
|
||||
return virtualChannel;
|
||||
}
|
||||
}
|
||||
}
|
126
Kha/Backends/HTML5/kha/audio2/VirtualStreamChannel.hx
Normal file
126
Kha/Backends/HTML5/kha/audio2/VirtualStreamChannel.hx
Normal file
@ -0,0 +1,126 @@
|
||||
package kha.audio2;
|
||||
|
||||
import kha.js.AEAudioChannel;
|
||||
import kha.audio1.AudioChannel;
|
||||
|
||||
enum abstract PlayMode(Int) {
|
||||
var Stopped;
|
||||
var Paused;
|
||||
var Playing;
|
||||
}
|
||||
|
||||
class VirtualStreamChannel implements kha.audio1.AudioChannel {
|
||||
var aeChannel: AEAudioChannel;
|
||||
var mode = PlayMode.Playing;
|
||||
var lastTickTime: Float;
|
||||
var lastPosition: Float;
|
||||
var looping: Bool;
|
||||
|
||||
public function new(aeChannel: AEAudioChannel, looping: Bool) {
|
||||
this.aeChannel = aeChannel;
|
||||
this.looping = looping;
|
||||
lastTickTime = Scheduler.realTime();
|
||||
lastPosition = 0;
|
||||
}
|
||||
|
||||
public function wake(): Void {
|
||||
updatePosition();
|
||||
aeChannel.position = lastPosition;
|
||||
aeChannel.play();
|
||||
}
|
||||
|
||||
function updatePosition(): Void {
|
||||
var now = Scheduler.realTime();
|
||||
switch (mode) {
|
||||
case Stopped:
|
||||
lastPosition = 0;
|
||||
case Paused:
|
||||
// nothing
|
||||
case Playing:
|
||||
lastPosition += now - lastTickTime;
|
||||
while (lastPosition > length) {
|
||||
lastPosition -= length;
|
||||
}
|
||||
}
|
||||
lastTickTime = now;
|
||||
}
|
||||
|
||||
public function play(): Void {
|
||||
if (SystemImpl.mobileAudioPlaying) {
|
||||
aeChannel.play();
|
||||
}
|
||||
else {
|
||||
updatePosition();
|
||||
mode = Playing;
|
||||
}
|
||||
}
|
||||
|
||||
public function pause(): Void {
|
||||
if (SystemImpl.mobileAudioPlaying) {
|
||||
aeChannel.pause();
|
||||
}
|
||||
else {
|
||||
updatePosition();
|
||||
mode = Paused;
|
||||
}
|
||||
}
|
||||
|
||||
public function stop(): Void {
|
||||
if (SystemImpl.mobileAudioPlaying) {
|
||||
aeChannel.stop();
|
||||
}
|
||||
else {
|
||||
updatePosition();
|
||||
mode = Stopped;
|
||||
}
|
||||
}
|
||||
|
||||
public var length(get, never): Float; // Seconds
|
||||
|
||||
function get_length(): Float {
|
||||
return aeChannel.length;
|
||||
}
|
||||
|
||||
public var position(get, set): Float; // Seconds
|
||||
|
||||
function get_position(): Float {
|
||||
if (SystemImpl.mobileAudioPlaying) {
|
||||
return aeChannel.position;
|
||||
}
|
||||
else {
|
||||
updatePosition();
|
||||
return lastPosition;
|
||||
}
|
||||
}
|
||||
|
||||
function set_position(value: Float): Float {
|
||||
if (SystemImpl.mobileAudioPlaying) {
|
||||
return aeChannel.position = value;
|
||||
}
|
||||
else {
|
||||
updatePosition();
|
||||
return lastPosition = value;
|
||||
}
|
||||
}
|
||||
|
||||
public var volume(get, set): Float;
|
||||
|
||||
function get_volume(): Float {
|
||||
return aeChannel.volume;
|
||||
}
|
||||
|
||||
function set_volume(value: Float): Float {
|
||||
return aeChannel.volume = value;
|
||||
}
|
||||
|
||||
public var finished(get, never): Bool;
|
||||
|
||||
function get_finished(): Bool {
|
||||
if (SystemImpl.mobileAudioPlaying) {
|
||||
return aeChannel.finished;
|
||||
}
|
||||
else {
|
||||
return mode == Stopped || (!looping && position >= length);
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user