pxt-common-packages 13.2.5 → 13.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/libs/base/pxtbase.h +17 -1
- package/libs/mixer/instrument.ts +31 -27
- package/package.json +1 -1
package/libs/base/pxtbase.h
CHANGED
|
@@ -46,6 +46,7 @@
|
|
|
46
46
|
|
|
47
47
|
#include <string.h>
|
|
48
48
|
#include <stdint.h>
|
|
49
|
+
#include <stddef.h> // offsetof
|
|
49
50
|
#include <math.h>
|
|
50
51
|
|
|
51
52
|
#ifdef POKY
|
|
@@ -552,7 +553,22 @@ class Segment {
|
|
|
552
553
|
TValue get(unsigned i) { return i < length ? data[i] : NULL; }
|
|
553
554
|
void set(unsigned i, TValue value);
|
|
554
555
|
|
|
555
|
-
unsigned getLength() {
|
|
556
|
+
unsigned getLength() {
|
|
557
|
+
// Layout pinned for the PXT compiler's Array.length fast path
|
|
558
|
+
// (_pxt_array_length_tagged in pxt/pxtcompiler/emitter/backthumb.ts).
|
|
559
|
+
// That fast path reads the element count directly out of the array
|
|
560
|
+
// object at a fixed byte offset instead of calling Array_::length:
|
|
561
|
+
// array object[0] = RefObject.vtable
|
|
562
|
+
// array object[sizeof(void*)] = RefCollection.head (this Segment)
|
|
563
|
+
// head[sizeof(TValue*)] = Segment.length
|
|
564
|
+
// so the length lives at object offset 2*sizeof(void*) == 8 on the
|
|
565
|
+
// 32-bit thumb target, read there as `ldrh r0, [r0, #8]`. If these
|
|
566
|
+
// structs are reordered, the offset in backthumb.ts must change too;
|
|
567
|
+
// these asserts fail the native build if that ever drifts.
|
|
568
|
+
STATIC_ASSERT(sizeof(RefObject) == sizeof(void *));
|
|
569
|
+
STATIC_ASSERT(offsetof(Segment, length) == sizeof(TValue *));
|
|
570
|
+
return length;
|
|
571
|
+
};
|
|
556
572
|
void setLength(unsigned newLength);
|
|
557
573
|
|
|
558
574
|
void push(TValue value) { set(length, value); }
|
package/libs/mixer/instrument.ts
CHANGED
|
@@ -619,6 +619,18 @@ namespace music.sequencer {
|
|
|
619
619
|
timePoints.push(nextALTime);
|
|
620
620
|
nextALTime += ampLFOInterval;
|
|
621
621
|
}
|
|
622
|
+
// This can happen if our attack + decay time is greater than gate length. Make sure we start
|
|
623
|
+
// the release stage on time
|
|
624
|
+
else if (time < gateLength) {
|
|
625
|
+
time = gateLength;
|
|
626
|
+
timePoints.push(gateLength);
|
|
627
|
+
}
|
|
628
|
+
// If we reach this point, the only thing left is the end of the release stage
|
|
629
|
+
else {
|
|
630
|
+
time = totalDuration;
|
|
631
|
+
timePoints.push(totalDuration);
|
|
632
|
+
}
|
|
633
|
+
|
|
622
634
|
|
|
623
635
|
|
|
624
636
|
if (time >= totalDuration) {
|
|
@@ -669,18 +681,18 @@ namespace music.sequencer {
|
|
|
669
681
|
|
|
670
682
|
let nextAmp: number;
|
|
671
683
|
let nextPitch: number;
|
|
684
|
+
let ptr = 0;
|
|
672
685
|
const out = control.createBuffer(BUFFER_SIZE * timePoints.length);
|
|
673
686
|
for (let i = 1; i < timePoints.length; i++) {
|
|
674
687
|
if (timePoints[i] - prevTime < 5) {
|
|
675
|
-
prevTime = timePoints[i];
|
|
676
688
|
continue;
|
|
677
689
|
}
|
|
678
690
|
|
|
679
691
|
nextAmp = instrumentVolumeAtTime(instrument, gateLength, timePoints[i], volume) | 0;
|
|
680
692
|
nextPitch = instrumentPitchAtTime(instrument, noteFrequency, gateLength, timePoints[i]) | 0
|
|
681
|
-
addNote(
|
|
693
|
+
ptr = addNote(
|
|
682
694
|
out,
|
|
683
|
-
|
|
695
|
+
ptr,
|
|
684
696
|
(timePoints[i] - prevTime) | 0,
|
|
685
697
|
prevAmp,
|
|
686
698
|
nextAmp,
|
|
@@ -697,17 +709,19 @@ namespace music.sequencer {
|
|
|
697
709
|
|
|
698
710
|
// Finally, add one extra step to move the amplitude to 0 without
|
|
699
711
|
// clipping just in case the amp LFO caused it to be nonzero
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
712
|
+
if (prevAmp > 0) {
|
|
713
|
+
ptr = addNote(
|
|
714
|
+
out,
|
|
715
|
+
ptr,
|
|
716
|
+
10,
|
|
717
|
+
prevAmp,
|
|
718
|
+
0,
|
|
719
|
+
instrument.waveform,
|
|
720
|
+
prevPitch,
|
|
721
|
+
255,
|
|
722
|
+
prevPitch
|
|
723
|
+
)
|
|
724
|
+
}
|
|
711
725
|
return out;
|
|
712
726
|
}
|
|
713
727
|
|
|
@@ -783,7 +797,7 @@ namespace music.sequencer {
|
|
|
783
797
|
* of the sound instructions will be longer than this if the amplitude envelope of the
|
|
784
798
|
* instrument has a nonzero release time
|
|
785
799
|
*/
|
|
786
|
-
function envelopeValueAtTime(envelope: Envelope, time: number, gateLength: number) {
|
|
800
|
+
function envelopeValueAtTime(envelope: Envelope, time: number, gateLength: number): number {
|
|
787
801
|
// ADSR envelopes consist of 4 stages. They are (in order):
|
|
788
802
|
// 1. The attack stage, where the value starts at 0 and rises to the maximum value
|
|
789
803
|
// 2. The decay stage, where the value falls from the maximum value to the sustain value
|
|
@@ -796,19 +810,9 @@ namespace music.sequencer {
|
|
|
796
810
|
// First check to see if we are already in the release stage
|
|
797
811
|
if (time > gateLength) {
|
|
798
812
|
if (time - gateLength > envelope.release) return 0;
|
|
799
|
-
|
|
800
|
-
// Did the gate length end before the attack stage finished?
|
|
801
|
-
else if (time < envelope.attack) {
|
|
802
|
-
const height = (envelope.amplitude / envelope.attack) * gateLength;
|
|
803
|
-
return height - ((height / envelope.release) * (time - gateLength))
|
|
804
|
-
}
|
|
805
|
-
// Did the gate length end before the decay stage finished?
|
|
806
|
-
else if (time < envelope.attack + envelope.decay) {
|
|
807
|
-
const height2 = envelope.amplitude - ((envelope.amplitude - adjustedSustain) / envelope.decay) * (gateLength - envelope.attack);
|
|
808
|
-
return height2 - ((height2 / envelope.release) * (time - gateLength))
|
|
809
|
-
}
|
|
810
813
|
else {
|
|
811
|
-
|
|
814
|
+
const releaseStartLevel = envelopeValueAtTime(envelope, gateLength, gateLength);
|
|
815
|
+
return releaseStartLevel - (releaseStartLevel / envelope.release) * (time - gateLength)
|
|
812
816
|
}
|
|
813
817
|
}
|
|
814
818
|
else if (time < envelope.attack) {
|