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.
@@ -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() { return length; };
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); }
@@ -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
- (i - 1) * 12,
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
- addNote(
701
- out,
702
- (timePoints.length - 1) * 12,
703
- 10,
704
- prevAmp,
705
- 0,
706
- instrument.waveform,
707
- prevPitch,
708
- 255,
709
- prevPitch
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
- return adjustedSustain - (adjustedSustain / envelope.release) * (time - gateLength)
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) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pxt-common-packages",
3
- "version": "13.2.5",
3
+ "version": "13.2.7",
4
4
  "description": "Microsoft MakeCode (PXT) common packages",
5
5
  "keywords": [
6
6
  "MakeCode",