class
RingBuffer {
constructor(type, count, subbuffercount, sharedvarssab, sab){
this
._capacity = count;
this
._size = count + 1;
this
._sab = [];
this
._buffer = [];
this
._subbuffercount = subbuffercount;
this
._sharedvarssab = sharedvarssab;
this
._sharedvarsuint32 =
new
Uint32Array(
this
._sharedvarssab);
this
._sab = sab;
for
(
let
i = 0; i <
this
._subbuffercount; i++) {
this
._buffer[i] =
new
type(
this
._sab[i]);
}
}
static
create(type, count, subbuffercount) {
const sharedvarssab =
new
SharedArrayBuffer(8);
let
sab = [];
const size = count+1;
for
(
let
i = 0; i < subbuffercount; i++) {
sab[i] =
new
SharedArrayBuffer(type.BYTES_PER_ELEMENT * (size));
}
return
new
RingBuffer(type, count, subbuffercount, sharedvarssab, sab);
}
to() {
return
{
'_capacity'
:
this
._capacity,
'_subbuffercount'
:
this
._subbuffercount,
'_sharedvarssab'
:
this
._sharedvarssab,
'_sab'
:
this
._sab
};
}
_writeindex() {
return
Atomics.load(
this
._sharedvarsuint32, 0);
}
_readindex() {
return
Atomics.load(
this
._sharedvarsuint32, 1);
}
getcount() {
const wi =
this
._writeindex();
const ri =
this
._readindex();
return
wi >= ri ? wi-ri : (
this
._size - (ri - wi));
}
getspace() {
return
this
._capacity -
this
.getcount();
}
_AssertSameArrayCount(param) {
if
(param.length ===
this
._subbuffercount)
return
;
throw
(
"Different Array Counts! param "
+ param +
" subbuffercount "
+
this
._subbuffercount);
}
}
class
RingBufferReader {
constructor(rb) {
this
._rb = rb;
}
getcount() {
return
this
._rb.getcount();
}
getspace() {
return
this
._rb.getspace();
}
_setreadindex(newval) {
Atomics.store(
this
._rb._sharedvarsuint32, 1, newval);
}
read(destarrs, max, destoffset) {
this
._rb._AssertSameArrayCount(destarrs);
destoffset = destoffset || 0;
const destmax = destarrs[0].length - destoffset;
max = max || destmax;
const tocopy = Math.min(destmax,
this
._rb.getcount(), max);
if
(tocopy === 0)
return
0;
let
readindex =
this
._rb._readindex();
const nextReadIndex = readindex + tocopy;
if
(nextReadIndex <
this
._rb._buffer[0].length) {
for
(
let
i = 0; i < destarrs.length; i++) {
destarrs[i].set(
this
._rb._buffer[i].subarray(readindex, nextReadIndex), destoffset);
}
readindex += tocopy;
}
else
{
const overflow = nextReadIndex -
this
._rb._buffer[0].length;
let
newreadindex;
for
(
let
i = 0; i < destarrs.length; i++) {
const firstHalf =
this
._rb._buffer[i].subarray(readindex);
const secondHalf =
this
._rb._buffer[i].subarray(0, overflow);
destarrs[i].set(firstHalf, destoffset);
destarrs[i].set(secondHalf, firstHalf.length+destoffset);
newreadindex = secondHalf.length;
}
readindex = newreadindex;
}
this
._setreadindex(readindex);
return
tocopy;
}
}
class
RingBufferWriter {
constructor(rb) {
this
._rb = rb;
}
getcount() {
return
this
._rb.getcount();
}
getspace() {
return
this
._rb.getspace();
}
_setwriteindex(newval) {
Atomics.store(
this
._rb._sharedvarsuint32, 0, newval);
}
write(arrs, max) {
this
._rb._AssertSameArrayCount(arrs);
max = max || arrs[0].length;
const count = Math.min(max, arrs[0].length);
const space =
this
._rb.getspace();
if
(count > space) {
throw
(
"Tried to write too much data, count "
+ count +
" space "
+ space);
}
let
writeindex =
this
._rb._writeindex();
if
((writeindex+count) <
this
._rb._size) {
for
(
let
i = 0; i < arrs.length; i++) {
this
._rb._buffer[i].set(arrs[i].subarray(0, count), writeindex);
}
writeindex += count;
}
else
{
const splitIndex =
this
._rb._size - writeindex;
let
newwriteindex;
for
(
let
i = 0; i < arrs.length; i++) {
const firstHalf = arrs[i].subarray(0, splitIndex);
const secondHalf = arrs[i].subarray(splitIndex, count);
this
._rb._buffer[i].set(firstHalf, writeindex);
this
._rb._buffer[i].set(secondHalf);
newwriteindex = secondHalf.length;
}
writeindex = newwriteindex;
}
this
._setwriteindex(writeindex);
}
}
class
Float32AudioRingBuffer {
constructor(rb, samplerate, messagerb){
this
._rb = rb;
this
._samplerate = samplerate;
this
._messages = messagerb;
this
._MSG = {
'SKIP'
: 1
};
}
getcount() {
return
this
._rb.getcount();
}
gettime() {
const count =
this
.getcount();
return
count /
this
._samplerate;
}
getspace() {
return
this
._rb.getspace();
}
static
createpreq(framecount, numberofchannels) {
return
{
'rb'
: RingBuffer.create(Float32Array, framecount, numberofchannels),
'messages'
: RingBuffer.create(Uint32Array, 4095, 2)
};
}
}
class
Float32AudioRingBufferReader
extends
Float32AudioRingBuffer {
constructor(rb, samplerate, messages){
super
(rb, samplerate, messages);
this
._msgreader =
new
RingBufferReader(messages);
this
._reader =
new
RingBufferReader(rb);
this
._inmessage = [
new
Uint32Array(1),
new
Uint32Array(1)];
}
static
create(framecount, numberofchannels, samplerate) {
const prereq =
super
.createpreq(framecount, numberofchannels);
return
new
Float32AudioRingBufferReader(prereq.rb, samplerate, prereq.messages);
}
static
from
(obj) {
const rb =
new
RingBuffer(Float32Array, obj._rb._capacity, obj._rb._subbuffercount, obj._rb._sharedvarssab, obj._rb._sab);
const messages =
new
RingBuffer(Uint32Array, obj._messages._capacity, obj._messages._subbuffercount, obj._messages._sharedvarssab, obj._messages._sab);
return
new
Float32AudioRingBufferReader(rb, obj._samplerate, messages);
}
_setreadhead(index) {
this
._reader._setreadindex(index);
}
read(destarrs, max, destoffset) {
return
this
._reader.read(destarrs, max, destoffset);
}
processmessages() {
while
(
this
._msgreader.read(
this
._inmessage, 1) > 0) {
if
(
this
._inmessage[0][0] ===
this
._MSG.SKIP) {
this
._setreadhead(
this
._inmessage[1][0]);
}
}
}
}
class
Float32AudioRingBufferWriter
extends
Float32AudioRingBuffer{
constructor(rb, samplerate, messages){
super
(rb, samplerate, messages);
this
._msgwriter =
new
RingBufferWriter(messages);
this
._writer =
new
RingBufferWriter(rb);
this
._outmessage = [
new
Uint32Array(1),
new
Uint32Array(1)];
}
static
create(framecount, numberofchannels, samplerate) {
const prereq =
super
.createpreq(framecount, numberofchannels);
return
new
Float32AudioRingBufferWriter(prereq.rb, samplerate, prereq.messages);
}
to() {
return
{
'_rb'
:
this
._rb.to(),
'_messages'
:
this
._messages.to(),
'_samplerate'
:
this
._samplerate
};
}
write(arrs, max) {
return
this
._writer.write(arrs, max);
}
sendmessage(msgid, data) {
this
._outmessage[0][0] = msgid;
this
._outmessage[1][0] = data;
this
._msgwriter.write(
this
._outmessage);
}
reset() {
this
.sendmessage(
this
._MSG.SKIP,
this
._rb._writeindex());
}
}
export
{RingBuffer, Float32AudioRingBufferReader, Float32AudioRingBufferWriter};