Skip to content

Commit a9f729a

Browse files
authored
fix: Fix queue and list handling for kotlin (#2085)
1 parent 3644a11 commit a9f729a

File tree

5 files changed

+72
-41
lines changed

5 files changed

+72
-41
lines changed

src.kotlin/alphaTab/android/src/main/java/alphaTab/collections/List.kt

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,43 @@
11
package alphaTab.collections
22

3+
internal class ArrayListWithRemoveRange<T> : ArrayList<T> {
4+
5+
constructor() : super()
6+
constructor(c: Collection<T>) : super(c)
7+
8+
public override fun removeRange(startIndex:Int, endIndex:Int) {
9+
super.removeRange(startIndex, endIndex);
10+
}
11+
}
12+
313
public class List<T> : Iterable<T> {
4-
internal val _data: MutableList<T>
14+
internal val _data: ArrayListWithRemoveRange<T>
515

616
val length: Double
717
get() = _data.size.toDouble()
818

919
public constructor() {
10-
_data = ArrayList()
20+
_data = ArrayListWithRemoveRange()
1121
}
1222

1323
public constructor(vararg items: T) {
14-
_data = items.toMutableList()
24+
_data = items.toCollection(ArrayListWithRemoveRange())
1525
}
1626

1727
@Suppress("UNCHECKED_CAST")
1828
public constructor(size: Int) {
19-
_data = ArrayList()
29+
_data = ArrayListWithRemoveRange()
2030
var remaining = size
2131
while (remaining-- > 0) {
2232
_data.add(null as T)
2333
}
2434
}
2535

2636
public constructor(items: Iterable<T>) {
27-
_data = items.toMutableList()
37+
_data = items.toCollection(ArrayListWithRemoveRange())
2838
}
2939

30-
internal constructor(items: MutableList<T>) {
40+
internal constructor(items: ArrayListWithRemoveRange<T>) {
3141
_data = items
3242
}
3343

@@ -72,7 +82,7 @@ public class List<T> : Iterable<T> {
7282
}
7383

7484
public fun pop(): T {
75-
return _data.removeLast()
85+
return _data.removeAt(_data.lastIndex)
7686
}
7787

7888
public fun unshift(item: T) {
@@ -111,11 +121,11 @@ public class List<T> : Iterable<T> {
111121
}
112122

113123
public fun slice(): List<T> {
114-
return List(ArrayList(_data))
124+
return List(ArrayListWithRemoveRange(_data))
115125
}
116126

117127
public fun slice(start: Double): List<T> {
118-
return List(_data.subList(start.toInt(), _data.size))
128+
return List(ArrayListWithRemoveRange(_data.subList(start.toInt(), _data.size)))
119129
}
120130

121131
public fun shift(): T {
@@ -128,7 +138,7 @@ public class List<T> : Iterable<T> {
128138
actualStart += _data.size
129139
}
130140

131-
_data.subList(start.toInt(), (start + deleteCount).toInt()).clear()
141+
_data.removeRange(start.toInt(), (start + deleteCount).toInt())
132142
_data.addAll(start.toInt(), newElements.toList())
133143
}
134144

src/synth/AlphaSynth.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -557,14 +557,15 @@ export class AlphaSynthBase implements IAlphaSynth {
557557
if (isSeek) {
558558
this._playedEventsQueue.clear();
559559
} else {
560-
const playedEvents = new Queue<MidiEvent>();
561-
while (!this._playedEventsQueue.isEmpty && this._playedEventsQueue.peek().time < currentTime) {
562-
const synthEvent = this._playedEventsQueue.dequeue();
563-
playedEvents.enqueue(synthEvent.event);
560+
const playedEvents: MidiEvent[] = [];
561+
while (!this._playedEventsQueue.isEmpty && this._playedEventsQueue.peek()!.time < currentTime) {
562+
const synthEvent = this._playedEventsQueue.dequeue()!;
563+
playedEvents.push(synthEvent.event);
564564
}
565-
if (!playedEvents.isEmpty) {
565+
if (playedEvents.length > 0) {
566+
playedEvents.reverse();
566567
(this.midiEventsPlayed as EventEmitterOfT<MidiEventsPlayedEventArgs>).trigger(
567-
new MidiEventsPlayedEventArgs(playedEvents.toArray())
568+
new MidiEventsPlayedEventArgs(playedEvents)
568569
);
569570
}
570571
}

src/synth/BackingTrackPlayer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ class BackingTrackAudioSynthesizer implements IAudioSampleSynthesizer {
9898
public fakeSynthesize(): SynthEvent[] {
9999
const processedEvents: SynthEvent[] = [];
100100
while (!this._midiEventQueue.isEmpty) {
101-
const m: SynthEvent = this._midiEventQueue.dequeue();
101+
const m: SynthEvent = this._midiEventQueue.dequeue()!;
102102
if (m.isMetronome && this.metronomeVolume > 0) {
103103
// ignore metronome
104104
} else if (m.event) {

src/synth/ds/Queue.ts

Lines changed: 43 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,58 @@
1+
class QueueItem<T> {
2+
public value: T;
3+
public next?: QueueItem<T>;
4+
5+
public constructor(value: T) {
6+
this.value = value;
7+
}
8+
}
9+
110
export class Queue<T> {
2-
private _items: T[] = [];
3-
private _position: number = 0;
11+
private _head?: QueueItem<T>;
12+
private _tail?: QueueItem<T>;
413

5-
public isEmpty: boolean = true;
14+
public get isEmpty() {
15+
return this._head === undefined;
16+
}
617

718
public clear() {
8-
this._items = [];
9-
this._position = 0;
10-
this.isEmpty = true;
19+
this._head = undefined;
20+
this._tail = undefined;
1121
}
1222

1323
public enqueue(item: T) {
14-
this.isEmpty = false;
15-
this._items.push(item);
24+
const queueItem = new QueueItem<T>(item);
25+
if (this._tail) {
26+
// not empty -> add after tail
27+
this._tail!.next = queueItem;
28+
this._tail = queueItem;
29+
} else {
30+
// empty -> new item takes head and tail
31+
this._head = queueItem;
32+
this._tail = queueItem;
33+
}
1634
}
1735

18-
public peek(): T {
19-
return this._items[this._position];
36+
public peek(): T | undefined {
37+
const head = this._head;
38+
if (!head) {
39+
return undefined;
40+
}
41+
return head.value;
2042
}
2143

22-
public dequeue(): T {
23-
const item = this._items[this._position];
24-
this._position++;
25-
if (this._position >= this._items.length / 2) {
26-
this._items = this._items.slice(this._position);
27-
this._position = 0;
44+
public dequeue(): T | undefined {
45+
const head = this._head;
46+
if (!head) {
47+
return undefined;
2848
}
29-
this.isEmpty = this._items.length === 0;
30-
return item;
31-
}
3249

33-
public toArray(): T[] {
34-
const items = this._items.slice(this._position);
35-
items.reverse();
36-
return items;
50+
const newHead:QueueItem<T>|undefined = head.next;
51+
this._head = newHead;
52+
// last item removed?
53+
if (!newHead) {
54+
this._tail = undefined;
55+
}
56+
return head.value;
3757
}
3858
}

src/synth/synthesis/TinySoundFont.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ export class TinySoundFont implements IAudioSampleSynthesizer {
185185
// process in micro-buffers
186186
// process events for first microbuffer
187187
while (!this._midiEventQueue.isEmpty) {
188-
const m: SynthEvent = this._midiEventQueue.dequeue();
188+
const m: SynthEvent = this._midiEventQueue.dequeue()!;
189189
if (m.isMetronome && this.metronomeVolume > 0) {
190190
this.channelNoteOff(SynthConstants.MetronomeChannel, SynthConstants.MetronomeKey);
191191
this.channelNoteOn(SynthConstants.MetronomeChannel, SynthConstants.MetronomeKey, 95 / 127);

0 commit comments

Comments
 (0)