First time here? Check out the FAQ!
x

Accessing full contents of Two Dimensional arrays

+1 vote
790 views
Is it possible to select the entire coontents of Array1 Or Array2 to  with a !hotVariable to populate a parameter field?

 

Ty
asked Aug 20, 2019 in Capytalk & Smalltalk by rafe-mcdonald (Practitioner) (470 points)
edited Aug 23, 2019 by rafe-mcdonald

4 Answers

+2 votes

No you can't.

Or rather, you can achieve that result but you can't simply choose an array from an array of arrays with an !EventValue.

"This doesn't work"

!Select of: #(
    #( 1 2 3)
    #( 4 5 6))

The reason is that the answer (or result) of any Capytalk expression is always a number. A Capytalk expression cannot return an Array (or String or any other data type).

To select values from a two-dimensional array you need to include some Capytalk within the array. 

eg.
Say you want to select a single number from this array:

#( 
    (0.0 0.1 0.2 0.3)
    (1.0 1.1 1.2 1.3)
    (2.0 2.1 2.2 2.3)
)

 

The way you would do it is like this:

 

!Y of: #(
    {!X of: (0.0 0.1 0.2 0.3)}
    {!X of: (1.0 1.1 1.2 1.3)}
    {!X of: (2.0 2.1 2.2 2.3)}
)

 

In this case if !X is 1 and !Y is 2 the result would be 2.1 (of: is zero based).

(We enclose the "!X of: ..." expressions in curly brackets {}, because arrays in Smalltalk/Capytalk are space delimited. Without the {}s Smalltalk would try to interpret the !X as an element of the array followed by "of:" as another element, which doesn't make sense.)

This works because all of the "!X of:..." expressions return a single number and the "Y of:..." then chooses a single number from the array of single numbers created by the "!X of:..." expressions. 

You can select an entire array with an !EventValue in a parameter that expects an array (eg. the parameters of the ModalFilter).

Let's say you wanted to select one of the arrays from the example array above, eg. (1.0 1.1 1.2 1.3).

 

You would do that like this:

#(
    {!Select of: #(0.0 1.0 2.0)}
    {!Select of: #(0.1 1.1 2.1)}
    {!Select of: #(0.2 1.2 2.2)}
    {!Select of: #(0.3 1.3 2.3)}
)

 

Here the structure of the array is constructed by Smalltalk at compile time. The contents of each element of that array is selected at runtime by Capytalk. Again each Capytalk expression ("!Select of:...") is only returning a single number. 

Notice though to do this we've had to transpose the structure of our original array. The columns become rows and the rows become columns. 

If you have a lot of data already structured in the arrays you want to select, like the original example, then it can be a bit of a pain to transpose the array by hand. 

 

Here's a bit of Smalltalk that transposes arrays:

| transposer myArr |

"First we define a Smalltalk block (like a function or procedure) that transposes arrays"
transposer := [:arr|
    (1 to: arr first size) collect: [:column| arr collect: [:row| row at: column]]
].

"Here's our test array"
myArr := #(
    #( 1 2 3 4)
    #(11 12 13 14)
    #(21 22 23 24)).

"Now we run the function on our test array"
transposer value: myArr

 

 

So let's put this all together for the example of the ModeAmps field of the ModalFilter.

 

{
| amps transposedAmps transposer |

"Our sets of amplitudes:"
amps := #(
    #(0.8 0.7 0.5 0.21 0.11 0.09)
    #(0.75 0.65 0.2 0.21 0.1 0.03)
    #(0.65 0.63 0.45 0.42 0.3 0.1)
).

"Define our transposer block"
transposer := [:arr|
    (1 to: arr first size) collect: [:column| arr collect: [:row| row at: column]]
].

"Create the transposed array"
transposedAmps := transposer value: amps.

"Now we insert the !Select EventValue into each row of the transposed array to select the elements we want."
transposedAmps collect: [:row| !Select of: row]
}

 

 

If you compile (CMD-Y) this code you get:​

(
  !Select of: #( 0.8 0.75 0.65 ) 
  !Select of: #( 0.7 0.65 0.63 ) 
  !Select of: #( 0.5 0.2 0.45 ) 
  !Select of: #( 0.21 0.21 0.42 ) 
  !Select of: #( 0.11 0.1 0.3 ) 
  !Select of: #( 0.09 0.03 0.1 )
 )
 

(I've reformatted that to make it easier to read.)

answered Aug 21, 2019 by alan-jackson (Virtuoso) (15,840 points)
edited Aug 21, 2019 by alan-jackson
thanks Alan  - i posted the above querry just prior to you sharing your solution via our Kyma Kata slack group and I was going to post your solution today once I got it working.

btw just re-listening to your break down of Carla's code in the Vocal formant modal filter sound

Extremely educational

Thanks again!
No worries. I think it's a good question. I've ended up using two dimensional arrays many times. You might want to change the title to something that's more easily searchable.
To your point regarding the title of the post, which I have now updated;  I selected the "ask a related question" parameter and I mistakenly thought my post was simply going to add to the post I had searched.
0 votes
https://kyma.symbolicsound.com/qa/1063/how-to-create-an-array-that-selects-from-arrays

 

I am updating this thread for future members' queries as the link is  a related topic worth invesitgating if you are working with Multi-dimesional arrays.
answered Aug 23, 2019 by rafe-mcdonald (Practitioner) (470 points)
0 votes
I got the arrays rearranger working just great Thanks Alan but now I get this error when I adapt the array to have additional capytalk terms.  

 

What  is odd that it compiles in a text editor  and prints the output array that i want but throws an error in the sound file so I must have a logic issue with the expression?

i get the error message:  " the message # isEmpty, sent to nil, an instance of class undefined object, was not understood

amps:=  " declare two arrays" #(

#(

{ 0.453571  * ((!Keydown nextRandom ) *!ampRandScale)}   
{ 1.000000  * ((!Keydown nextRandom ) *!ampRandScale)}   
{ 0.880891  * ((!Keydown nextRandom ) *!ampRandScale)}   
{ 0.704994  * ((!Keydown nextRandom ) *!ampRandScale)}   
{ 0.377899  * ((!Keydown nextRandom ) *!ampRandScale)}   
{ 0.070784  * ((!Keydown nextRandom ) *!ampRandScale)}   
{ 0.253842  * ((!Keydown nextRandom ) *!ampRandScale)}   
{ 0.037125  * ((!Keydown nextRandom ) *!ampRandScale)}   
{ 0.013503  * ((!Keydown nextRandom ) *!ampRandScale)}   
{ 0.554033  * ((!Keydown nextRandom ) *!ampRandScale)}   
{ 0.065168  * ((!Keydown nextRandom ) *!ampRandScale)}   
{ 0.027005  * ((!Keydown nextRandom ) *!ampRandScale)}  ) " wine glass lg 4 225?"

#(
{ 1.000000  * ((!Keydown nextRandom ) *!ampRandScale)}   
{ 0.369840  * ((!Keydown nextRandom ) *!ampRandScale)}   
{ 0.314494  * ((!Keydown nextRandom ) *!ampRandScale)}   
{ 0.538913  * ((!Keydown nextRandom ) *!ampRandScale)}   
{ 0.414904  * ((!Keydown nextRandom ) *!ampRandScale)}   
{ 0.341613  * ((!Keydown nextRandom ) *!ampRandScale)}   
{ 0.449172  * ((!Keydown nextRandom ) *!ampRandScale)}   
{ 0.396428  * ((!Keydown nextRandom ) *!ampRandScale)}   
{ 0.281327  * ((!Keydown nextRandom ) *!ampRandScale)}   
{ 0.325485  * ((!Keydown nextRandom ) *!ampRandScale)}   
{ 0.575671  * ((!Keydown nextRandom ) *!ampRandScale)}   
{ 0.317452  * ((!Keydown nextRandom ) *!ampRandScale)}   )

).    " wine glass lg 200ml"
answered Aug 24, 2019 by rafe-mcdonald (Practitioner) (470 points)
edited Aug 24, 2019 by rafe-mcdonald
I figured out why the error is being thrown but not how its happening.  The output of the text editor is printing the arrays 'incorrectly' ( not as I expected)  so I'll have to reevaluate the steps.   The text editor misses two of the leading constant terms in an asymetrical way - hmm?
0 votes

Figured it out = > not sure why this is but the two objects that were missing from the evaluation were the leading 1.00000 amplitudes, located at location 1@1 and 1@ 2 ( representing the strongest normalized peaks ) but for whatever reason they were removed when the code evaluated.

When I changed those values to 0.99999 the code evaluates as expectedindecision odd!  The Obvious question is why would smalltalk not ' identify' those objects when capytalk expressions are concatenated within a block of code?

Is that a bug or just an unusual phenomenon in smalltalk?  The only thing that I could think of was that the value of 1 is being evaluated as a 'trigger', despite the object  of " * i" in the line of code.  The number 1 has special significance and is interpreted as a trigger when the code is evaluated?

Anyway for now happy to have solved the problem.

 

answered Aug 24, 2019 by rafe-mcdonald (Practitioner) (470 points)
edited Aug 25, 2019 by rafe-mcdonald
I think the reason why the " 1.0 * " parts are disappearing is because one times anything is itself so it's redundant and gets optimised out by the compiler.
right of course !!
...