11/*
2- Copyright 2020 The Matrix.org Foundation C.I.C.
2+ Copyright 2020, 2021 The Matrix.org Foundation C.I.C.
33
44Licensed under the Apache License, Version 2.0 (the "License");
55you may not use this file except in compliance with the License.
@@ -15,23 +15,47 @@ limitations under the License.
1515*/
1616
1717/**
18- * Quickly resample an array to have less data points. This isn't a perfect representation,
19- * though this does work best if given a large array to downsample to a much smaller array.
20- * @param {number[] } input The input array to downsample.
18+ * Quickly resample an array to have less/more data points. If an input which is larger
19+ * than the desired size is provided, it will be downsampled. Similarly, if the input
20+ * is smaller than the desired size then it will be upsampled.
21+ * @param {number[] } input The input array to resample.
2122 * @param {number } points The number of samples to end up with.
22- * @returns {number[] } The downsampled array.
23+ * @returns {number[] } The resampled array.
2324 */
2425export function arrayFastResample ( input : number [ ] , points : number ) : number [ ] {
25- // Heavily inpired by matrix-media-repo (used with permission)
26+ if ( input . length === points ) return input ; // short-circuit a complicated call
27+
28+ // Heavily inspired by matrix-media-repo (used with permission)
2629 // https://github.com/turt2live/matrix-media-repo/blob/abe72c87d2e29/util/util_audio/fastsample.go#L10
27- const everyNth = Math . round ( input . length / points ) ;
28- const samples : number [ ] = [ ] ;
29- for ( let i = 0 ; i < input . length ; i += everyNth ) {
30- samples . push ( input [ i ] ) ;
30+ let samples : number [ ] = [ ] ;
31+ if ( input . length > points ) {
32+ // Danger: this loop can cause out of memory conditions if the input is too small.
33+ const everyNth = Math . round ( input . length / points ) ;
34+ for ( let i = 0 ; i < input . length ; i += everyNth ) {
35+ samples . push ( input [ i ] ) ;
36+ }
37+ } else {
38+ // Smaller inputs mean we have to spread the values over the desired length. We
39+ // end up overshooting the target length in doing this, so we'll resample down
40+ // before returning. This recursion is risky, but mathematically should not go
41+ // further than 1 level deep.
42+ const spreadFactor = Math . ceil ( points / input . length ) ;
43+ for ( const val of input ) {
44+ samples . push ( ...arraySeed ( val , spreadFactor ) ) ;
45+ }
46+ samples = arrayFastResample ( samples , points ) ;
3147 }
48+
49+ // Sanity fill, just in case
3250 while ( samples . length < points ) {
3351 samples . push ( input [ input . length - 1 ] ) ;
3452 }
53+
54+ // Sanity trim, just in case
55+ if ( samples . length > points ) {
56+ samples = samples . slice ( 0 , points ) ;
57+ }
58+
3559 return samples ;
3660}
3761
@@ -178,6 +202,13 @@ export class GroupedArray<K, T> {
178202 constructor ( private val : Map < K , T [ ] > ) {
179203 }
180204
205+ /**
206+ * The value of this group, after all applicable alterations.
207+ */
208+ public get value ( ) : Map < K , T [ ] > {
209+ return this . val ;
210+ }
211+
181212 /**
182213 * Orders the grouping into an array using the provided key order.
183214 * @param keyOrder The key order.
0 commit comments