Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.javascript > #40631 > unrolled thread

sidetrack

Started byluserdroog <luser.droog@gmail.com>
First post2021-12-07 18:42 -0800
Last post2021-12-09 19:22 -0800
Articles 13 — 6 participants

Back to article view | Back to comp.lang.javascript


Contents

  sidetrack luserdroog <luser.droog@gmail.com> - 2021-12-07 18:42 -0800
    Re: sidetrack "Michael Haufe (TNO)" <tno@thenewobjective.com> - 2021-12-08 13:03 -0800
      Re: sidetrack luserdroog <luser.droog@gmail.com> - 2021-12-08 16:17 -0800
        Re: sidetrack luserdroog <luser.droog@gmail.com> - 2021-12-08 16:23 -0800
          Re: sidetrack "Michael Haufe (TNO)" <tno@thenewobjective.com> - 2021-12-08 21:38 -0800
            Re: sidetrack luserdroog <luser.droog@gmail.com> - 2021-12-09 17:39 -0800
              Re: sidetrack luserdroog <luser.droog@gmail.com> - 2021-12-09 17:44 -0800
              Re: sidetrack Scott Sauyet <scott@sauyet.com> - 2021-12-10 07:26 -0800
          Re: sidetrack Elhwen Dico <elhwen.dicote@gmail.com> - 2021-12-10 16:30 +0100
            Re: sidetrack Elhwen Dico <elhwen.dicote@gmail.com> - 2021-12-10 16:37 +0100
            Re: sidetrack Thomas 'PointedEars' Lahn <PointedEars@web.de> - 2021-12-11 01:56 +0100
              Re: sidetrack Julio Di Egidio <julio@diegidio.name> - 2021-12-11 10:12 +0100
    Re: sidetrack luserdroog <luser.droog@gmail.com> - 2021-12-09 19:22 -0800

#40631 — sidetrack

Fromluserdroog <luser.droog@gmail.com>
Date2021-12-07 18:42 -0800
Subjectsidetrack
Message-ID<06038aa0-e554-4cc7-b3cc-77fa0d3c143fn@googlegroups.com>
I'm making some progress at reconceiving my pianoroll app
to be a more coherent object based design. But also kinda
not making progress on it. I doodled up a sketch of the overall
structure of the MVC example but instead of working on that,
here's a "robust" function for decoding note names from letters
and producing a MIDI note number. 

It uses two minor tetrachords to construct the intervals of an 
aeolian scale then takes a running sum to get "fretstops" for 
each of the scale degrees. Then you index the resulting array
with 0 for 'a', 1 for 'b' etc, a little more twiddling and poof kazow
presto! The desired number comes out the other end.

Is there a better way to do the running_sum()? I was trying to
do an APL "scan" and doing a reduce() while building the result
backwards was the best I could come up with.

const major_tetrachord = [ 2, 2, 1 ];
const mixolydian_mode = [ ...major_tetrachord,
                          ...major_tetrachord,
                          2 ];
const minor_tetrachord = [ 2, 1, 2 ];
const aeolian_mode = [ ...minor_tetrachord,
                       ...minor_tetrachord ];
const scale = [ ...mixolydian_mode,
                ...mixolydian_mode,
                ...major_tetrachord ];

function running_sum( a ){
  return  a.reduce( (pre,cur)=>[ cur+pre[0], ...pre ], [0] ).reverse();
}
console.log(running_sum(aeolian_mode));
console.log(running_sum(scale));

function note( str, octave=0 ){
  var num = str.toLowerCase().charCodeAt(0) - 'a'.charCodeAt(0);
  var fromA = running_sum(aeolian_mode)[ num ] + 
              (str.length > 1  ? (str[1]=='#' ? 1 : -1)
                               : 0);
  var fromC = fromA + 9;
  return  octave*12 + (fromC >= 12 ? fromC - 12 : fromC);
}

console.log(note("a",0));
console.log(note("c#",0));
console.log(note("eb",0));

[toc] | [next] | [standalone]


#40636

From"Michael Haufe (TNO)" <tno@thenewobjective.com>
Date2021-12-08 13:03 -0800
Message-ID<93cb03fa-9811-4e19-8469-6e0a0b9cae19n@googlegroups.com>
In reply to#40631
On Tuesday, December 7, 2021 at 8:42:11 PM UTC-6, luser...@gmail.com wrote:

> Is there a better way to do the running_sum()? I was trying to 
> do an APL "scan" and doing a reduce() while building the result 
> backwards was the best I could come up with. 

A `reduceRight` method exists on arrays:

<https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/ReduceRight>

[toc] | [prev] | [next] | [standalone]


#40638

Fromluserdroog <luser.droog@gmail.com>
Date2021-12-08 16:17 -0800
Message-ID<f38be122-740c-448e-b9d4-3691bcad8964n@googlegroups.com>
In reply to#40636
On Wednesday, December 8, 2021 at 3:03:49 PM UTC-6, Michael Haufe (TNO) wrote:
> On Tuesday, December 7, 2021 at 8:42:11 PM UTC-6, luser...@gmail.com wrote: 
> 
> > Is there a better way to do the running_sum()? I was trying to 
> > do an APL "scan" and doing a reduce() while building the result 
> > backwards was the best I could come up with.
> A `reduceRight` method exists on arrays: 
> 
> <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/ReduceRight>

Hmm. The parameter names make that seem like the right choice. At least it gives
you an `accumulator`. But on closer inspection, reverse()'s `previousValue` behaves
exactly the same, and might have been (better IMO) called *accumulator*, too.

I could do it without reversing by just pushing each intermediate result (that's all
an APL scan is: an array of the intermediate results from a reduce operation, probably 
ought to have defined it more precisely in OP).

function running_sum( a ){
  var t = [];
  a.reduce( (pre,cur)=>{t.push(pre+cur),pre+cur} );
  return  t;
}

It's not a "one liner", but this is probably a bit more efficient AFAICT.
In APL, it's just `+\`.

[toc] | [prev] | [next] | [standalone]


#40639

Fromluserdroog <luser.droog@gmail.com>
Date2021-12-08 16:23 -0800
Message-ID<692463e5-c0df-4a6f-b6ad-e1cb1c96c92cn@googlegroups.com>
In reply to#40638
On Wednesday, December 8, 2021 at 6:17:07 PM UTC-6, luserdroog wrote:

> function running_sum( a ){ 
> var t = []; 
> a.reduce( (pre,cur)=>{t.push(pre+cur),pre+cur}

  , 0

> ); 
> return t; 
> } 
> 
> It's not a "one liner", but this is probably a bit more efficient AFAICT. 
> In APL, it's just `+\`.

Need to use initial value zero (or prepend the original first element).
I really think that's right, now.

[toc] | [prev] | [next] | [standalone]


#40640

From"Michael Haufe (TNO)" <tno@thenewobjective.com>
Date2021-12-08 21:38 -0800
Message-ID<b94ff525-ca41-4574-a77d-da1f7c37fbd2n@googlegroups.com>
In reply to#40639
On Wednesday, December 8, 2021 at 6:23:12 PM UTC-6, luser...@gmail.com wrote:
> On Wednesday, December 8, 2021 at 6:17:07 PM UTC-6, luserdroog wrote: 
> 
> > function running_sum( a ){ 
> > var t = []; 
> > a.reduce( (pre,cur)=>{t.push(pre+cur),pre+cur}
> , 0
> > ); 
> > return t; 
> > } 
> > 
> > It's not a "one liner", but this is probably a bit more efficient AFAICT. 
> > In APL, it's just `+\`.
> Need to use initial value zero (or prepend the original first element). 
> I really think that's right, now.

functionally:

const add = (left, right) => left + right

const sum = (xs) => xs.reduce(add,0)

sum([1,2,3,4,5]) // 15

[toc] | [prev] | [next] | [standalone]


#40645

Fromluserdroog <luser.droog@gmail.com>
Date2021-12-09 17:39 -0800
Message-ID<a01b7437-266b-47a5-90b3-6818a59ee7c1n@googlegroups.com>
In reply to#40640
On Wednesday, December 8, 2021 at 11:38:30 PM UTC-6, Michael Haufe (TNO) wrote:
> On Wednesday, December 8, 2021 at 6:23:12 PM UTC-6, luser...@gmail.com wrote: 
> > On Wednesday, December 8, 2021 at 6:17:07 PM UTC-6, luserdroog wrote: 
> > 
> > > function running_sum( a ){ 
> > > var t = []; 
> > > a.reduce( (pre,cur)=>{t.push(pre+cur),pre+cur} 
> > , 0 
> > > ); 
> > > return t; 
> > > } 
> > > 
> > > It's not a "one liner", but this is probably a bit more efficient AFAICT. 
> > > In APL, it's just `+\`. 
> > Need to use initial value zero (or prepend the original first element). 
> > I really think that's right, now.
> functionally: 
> 
> const add = (left, right) => left + right 
> 
> const sum = (xs) => xs.reduce(add,0) 
> 
> sum([1,2,3,4,5]) // 15

That does an APL reduce (coincidentally named) which looks like:

  +/

But I'm after the subtly different function does a "scan" or piece-wise
reduce. In APL, it's almost imperceptibly different:

  +\

(There's a joke that APL\360 was named with the backslash character
in there so the product name means "APL extends 360" if treated as
an APL program. \ means "extend" if the left and right are values, but
in the snippets under consideration \ means "scan" because the left 
(+) is a function and not a value. I will endeavor to stop talking about
APL after this message.)
 
To be more functional, I think it would look like this:

Array.prototype.scan = function( f ){
  return  this.map( (e,i,a)=>a.slice(0,i+1).reduce(f,0) );
}
const add = (left,right) => left + right

function running_sum( a ){
  return  [ 0, ...a.scan( add )];
}

(I forgot I also needed the result of running_sum() to start with a zero,
in addition to the zero that gets fed to reduce() to ensure the first 
element of the input array shows up in the output array.)

[toc] | [prev] | [next] | [standalone]


#40646

Fromluserdroog <luser.droog@gmail.com>
Date2021-12-09 17:44 -0800
Message-ID<54d48386-efba-4696-b99d-eaf8f7d152cdn@googlegroups.com>
In reply to#40645
On Thursday, December 9, 2021 at 7:39:22 PM UTC-6, luserdroog wrote:
> On Wednesday, December 8, 2021 at 11:38:30 PM UTC-6, Michael Haufe (TNO) wrote: 
> > On Wednesday, December 8, 2021 at 6:23:12 PM UTC-6, luser...@gmail.com wrote: 
> > > On Wednesday, December 8, 2021 at 6:17:07 PM UTC-6, luserdroog wrote: 
> > > 
> > > > function running_sum( a ){ 
> > > > var t = []; 
> > > > a.reduce( (pre,cur)=>{t.push(pre+cur),pre+cur} 
> > > , 0 
> > > > ); 
> > > > return t; 
> > > > } 
> > > > 
> > > > It's not a "one liner", but this is probably a bit more efficient AFAICT. 
> > > > In APL, it's just `+\`. 
> > > Need to use initial value zero (or prepend the original first element). 
> > > I really think that's right, now. 
> > functionally: 
> > 
> > const add = (left, right) => left + right 
> > 
> > const sum = (xs) => xs.reduce(add,0) 
> > 
> > sum([1,2,3,4,5]) // 15
> That does an APL reduce (coincidentally named) which looks like: 
> 
> +/ 
> 
> But I'm after the subtly different function does a "scan" or piece-wise 
> reduce. In APL, it's almost imperceptibly different: 
> 
> +\ 
> 
> (There's a joke that APL\360 was named with the backslash character 
> in there so the product name means "APL extends 360" if treated as 
> an APL program. \ means "extend" if the left and right are values, but 
> in the snippets under consideration \ means "scan" because the left 
> (+) is a function and not a value. I will endeavor to stop talking about 
> APL after this message.) 
> 
> To be more functional, I think it would look like this: 
> 
> Array.prototype.scan = function( f ){ 
> return this.map( (e,i,a)=>a.slice(0,i+1).reduce(f,0) ); 

dangitall.

> } 
> const add = (left,right) => left + right 
> 
> function running_sum( a ){ 
> return [ 0, ...a.scan( add )]; 
> } 
> 
> (I forgot I also needed the result of running_sum() to start with a zero, 
> in addition to the zero that gets fed to reduce() to ensure the first 
> element of the input array shows up in the output array.)

Erhm. We don't need that zero in reduce() anymore. The map() takes
care of that.

[toc] | [prev] | [next] | [standalone]


#40653

FromScott Sauyet <scott@sauyet.com>
Date2021-12-10 07:26 -0800
Message-ID<34bb7f81-ba88-4abf-abeb-ffd10bb84b5cn@googlegroups.com>
In reply to#40645
luser wrote:

> But I'm after the subtly different function does a "scan" or piece-wise 
> reduce. In APL, it's almost imperceptibly different: 
> [ ...] 
> To be more functional, I think it would look like this: 
> 
> Array.prototype.scan = function( f ){ 
> return this.map( (e,i,a)=>a.slice(0,i+1).reduce(f,0) ); 
> } 
> const add = (left,right) => left + right 
> 
> function running_sum( a ){ 
> return [ 0, ...a.scan( add )]; 
> } 

I find this much cleaner:

    const scan = (fn) => (init) => (xs) =>
      xs .reduce ((ys, x) => ((ys .push (fn (ys .at (-1), x))), ys), [init])

    const running_sum = scan ((a, b) => a + b) (0)

    running_sum ([1, 2, 3, 4, 5]) //=> [0, 1, 3, 6, 10, 15]


While this is more elegant:

    const scan = (fn) => (init) => (xs) =>
      xs .reduce ((ys, x) => [...ys, fn (ys .at (-1), x)], [init])

It will almost certainly be less efficient as it has to build a new 
array on each iteration.

If `Array.prototype.at` is not available in your environment, it's
trivial enough to write your own `last` function and replace
`ys .at (-1)` with `last (ys)`.


  -- Scott

[toc] | [prev] | [next] | [standalone]


#40654

FromElhwen Dico <elhwen.dicote@gmail.com>
Date2021-12-10 16:30 +0100
Message-ID<61b3727a$0$3675$426a74cc@news.free.fr>
In reply to#40639
function running_sum(a: number[]) {
	return a.reduce(
		(acc: number, current: number) => acc + current,
		0);
}

console.log(running_sum([1, 2, 3]));
console.log(running_sum([]));

Le 09/12/2021 à 01:23, luserdroog a écrit :
> On Wednesday, December 8, 2021 at 6:17:07 PM UTC-6, luserdroog wrote:
> 
>> function running_sum( a ){
>> var t = [];
>> a.reduce( (pre,cur)=>{t.push(pre+cur),pre+cur}
> 
>    , 0
> 
>> );
>> return t;
>> }
>>
>> It's not a "one liner", but this is probably a bit more efficient AFAICT.
>> In APL, it's just `+\`.
> 
> Need to use initial value zero (or prepend the original first element).
> I really think that's right, now.

[toc] | [prev] | [next] | [standalone]


#40655

FromElhwen Dico <elhwen.dicote@gmail.com>
Date2021-12-10 16:37 +0100
Message-ID<61b3741e$0$8893$426a74cc@news.free.fr>
In reply to#40654
const running_sum = (a) => a.reduce((acc, curr) => acc + curr, 0);

console.log(running_sum([1, 2, 3]));
console.log(running_sum([]));


Le 10/12/2021 à 16:30, Elhwen Dico a écrit :
> 
> function running_sum(a: number[]) {
>      return a.reduce(
>          (acc: number, current: number) => acc + current,
>          0);
> }
> 
> console.log(running_sum([1, 2, 3]));
> console.log(running_sum([]));
> 
> Le 09/12/2021 à 01:23, luserdroog a écrit :
>> On Wednesday, December 8, 2021 at 6:17:07 PM UTC-6, luserdroog wrote:
>>
>>> function running_sum( a ){
>>> var t = [];
>>> a.reduce( (pre,cur)=>{t.push(pre+cur),pre+cur}
>>
>>    , 0
>>
>>> );
>>> return t;
>>> }
>>>
>>> It's not a "one liner", but this is probably a bit more efficient 
>>> AFAICT.
>>> In APL, it's just `+\`.
>>
>> Need to use initial value zero (or prepend the original first element).
>> I really think that's right, now.
> 

[toc] | [prev] | [next] | [standalone]


#40657

FromThomas 'PointedEars' Lahn <PointedEars@web.de>
Date2021-12-11 01:56 +0100
Message-ID<1778291.atdPhlSkOF@PointedEars.de>
In reply to#40654
Elhwen Dico wrote:

> [top post]

Bats are supposed to post next door.

-- 
PointedEars
FAQ: <http://PointedEars.de/faq> | <http://PointedEars.de/es-matrix>
<https://github.com/PointedEars> | <http://PointedEars.de/wsvn/>
Twitter: @PointedEars2 | Please do not cc me./Bitte keine Kopien per E-Mail.

[toc] | [prev] | [next] | [standalone]


#40659

FromJulio Di Egidio <julio@diegidio.name>
Date2021-12-11 10:12 +0100
Message-ID<sp1q1p$o39$1@dont-email.me>
In reply to#40657
On 11/12/2021 01:56, Thomas 'PointedEars' Lahn wrote:
> Elhwen Dico wrote:
> 
>> [top post]
> 
> Bats are supposed to post next door.

Since of course he has posted the best code so far in this thread...

And that's all you do, you incompetent spamming retarded piece of shit.

*Troll Alert*

Julio

[toc] | [prev] | [next] | [standalone]


#40647

Fromluserdroog <luser.droog@gmail.com>
Date2021-12-09 19:22 -0800
Message-ID<23dc480c-f9f4-4920-bdb9-e7477b809d75n@googlegroups.com>
In reply to#40631
On Tuesday, December 7, 2021 at 8:42:11 PM UTC-6, luserdroog wrote:
> I'm making some progress at reconceiving my pianoroll app 
> to be a more coherent object based design. But also kinda 
> not making progress on it. I doodled up a sketch of the overall 
> structure of the MVC example but instead of working on that, 
> here's a "robust" function for decoding note names from letters 
> and producing a MIDI note number. 
> 
> It uses two minor tetrachords to construct the intervals of an 
> aeolian scale then takes a running sum to get "fretstops" for 
> each of the scale degrees. Then you index the resulting array 
> with 0 for 'a', 1 for 'b' etc, a little more twiddling and poof kazow 
> presto! The desired number comes out the other end. 

Revised and expanded code from OP. It can now produce an array
of midi note numbers given a chord name (like "Bbm" or "F#7").
Some explanation of how I'm using the scale and the chord template
is in this post:

  https://music.stackexchange.com/a/6181/1344

Adding Major 7th chords would require some reworking like starting
with a different mode. Another nice extension would be an option
for closed vs. open voicing or a spectrum or palette of voicings.



const major_tetrachord = [ 2, 2, 1 ];
const minor_tetrachord = [ 2, 1, 2 ];

//mode names according to Boethius
const ionian_mode = [ ...major_tetrachord,   //defined by Nicomachus as two disjunct
                      2,                     //tetrachords separated by a tone
                      ...major_tetrachord ];

const mixolydian_mode = [ ...major_tetrachord, //need this for 7th chords and stuff
                          ...major_tetrachord, //like A/E and C/G chords
                          2 ];

const aeolian_mode = [ ...minor_tetrachord,   //defined by Nicomachus as two conjoint
                       ...minor_tetrachord ]; //tetrachords

const long_mix_scale = [ ...mixolydian_mode,
                ...mixolydian_mode,
                ...major_tetrachord ];

const long_scale = ( scale )=>[ ...scale, ...scale, ...scale ];

Array.prototype.scan = function( f ){
  return  this.map( (e,i,a)=>a.slice(0,i+1).reduce(f) );
}
Array.prototype.scan_v2 = function( f ){
  var r = [];
  this.reduce( (left,right)=>{ var t = f(left,right); r.push(t); return  t; }, 0 );
  return  r;
}
const add = (left,right) => left + right
const running_sum = ( a ) => [ 0, ...a.scan( add ) ]

console.log(running_sum(aeolian_mode));
console.log(running_sum(long_mix_scale));
console.log(running_sum(long_scale(mixolydian_mode)));

function note( str, octave=0 ){
  var num = str.toUpperCase().charCodeAt(0) - 'A'.charCodeAt(0);
  var fromA = running_sum(aeolian_mode)[ num ] + 
              (str.length > 1  ? (str[1]=='#' ? 1 : -1)
                               : 0);
  var fromC = fromA + 9;
  return  octave*12 + (fromC >= 12 ? fromC - 12 : fromC);
}

function chord( str, octave=0 ){
  var off = 0;
  var tweak = 0;
  var is7th = 0;
  var twiddle = -3; //+9 (midi number of 'A') -12 (lower octave)

  var num = str.toUpperCase().charCodeAt(0) - 'A'.charCodeAt(0);
  var base = running_sum(aeolian_mode)[ num ];
  str = str.slice(1);

  if( str.length > 0 ){
    off = str[0]=='#'  ?  1
        : str[0]=='b'  ? -1
        : 0;
    if( off ){ str = str.slice(1); }
  }

  if( str.length > 0 && str[0]=='m' ){
    tweak = -1;
    str = str.slice(1);
  }

  if( str.length > 0 && str[0]=='7' ){
    is7th = 1;
  }

  var template = is7th ? [ 1,5,7,8,10,12,14,15 ]  //figured bass for chord shape
                       : [ 1,5,  8,10,12,   15 ];
  var mode = [ ...mixolydian_mode ];
  mode[1] += tweak; //minor chord uses a flat 3rd
  mode[2] -= tweak; //balance the adjacent interval
  //console.log( mode );
  //console.log( running_sum( mode ) );

  var scale = running_sum( long_scale( mode ) );
  //console.log( scale );

  var chord = template.map( x=> scale[x-1] + base + off + twiddle );
  chord = chord.map( x=> x+octave*12 );
  chord = chord.filter( x=> x>=0 );
  return  chord;
}

console.log(note("a",0));
console.log(note("c#",0));
console.log(note("eb",0));
console.log(chord("a"));
console.log(chord("am"));
console.log(chord("a7"));
console.log(chord("ebm7",4));


Output:
9
1
3
Array(5) [ 4, 9, 13, 16, 21 ]
Array(5) [ 4, 9, 12, 16, 21 ]
Array(7) [ 4, 7, 9, 13, 16, 19, 21 ]
Array(8) [ 51, 58, 61, 63, 66, 70, 73, 75 ]

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.javascript


csiph-web