GTCMT / DataToMusicAPI

MIT License
27 stars 5 forks source link

Using dtm data as parameters #15

Open taylorbf opened 7 years ago

taylorbf commented 7 years ago

Hi Taka, Great lib : ) I have a design question --

Some methods take DTM data as input, while others don't.

Let's use this as an example --

dtm.gen("sine").fit(10).amp(2)

I can use a dtm data object as input to the amp() method.

dtm.gen("sine").fit(10).amp( dtm.ri(200,0,1) )

But, there are other functions where I cannot use a dtm data object as input. fit() is one of those methods. This will not work:

dtm.gen("sine").fit( dtm.ri(1,5,10) ).amp(2)

I understand that

1) this is an odd use case, because .fit() needs exactly one number as input 2) I could use dtm.ri(1,5,10).get(0) to return the first number, which would work.

But I wonder what you think about the idea of allowing DTM arrays as inputs into more methods? This could become a more common use case if anyone wants to write DTM code that is evaluated more than once

Or, it could even open up new territories, for example, this could have a different 'fit' length for each of the 5 repetitions.

dtm.gen("line").rep(5).fit( dtm.ri(5,5,10) )

Let me know what you think!

ttsuchiya commented 7 years ago

Hi Ben, sorry for the delay... I was a bit occupied for the past few days. You are right about the fit / stretch methods not taking the dtm.data object, and I wasn't sure originally how to approach to the multiple-value problem.

But now, I think I have some use case of multi value input that might make sense: such as for creating envelope with complex rhythm / duration. Similar to your rep(5) approach, the input array with length N would apply the fit function for each input element, but by slicing the target (or source?) array into equal size chunks first (with fit(N) interpolation if necessary).

E.g.,

dtm.data(1,2,3).fit.step([2,3,4]) -> [1,1, 2,2,2, 3,3,3,3]
dtm.data(1,2,3,4,5).fit.step([2,3]) -> [1,1, 5,5,5] // downsampels the target to [1,5] first
dtm.data(1,2,3).fit.line([3,5]) -> [1,1.5,2, 2,2.25,2.5,2.75,3]

The third example has a repeated value 2 as it's a shared end/start point. This could be undesirable. Anyway, I'll try implementing this idea and ask for your evaluation this week.

Also, your rep(5) solution could be done in this way:

a = dtm.ri(5,5,10) // fit lengths array

dtm.gen('line').copy(5) // creates 5 copies into separate columns
  .each((d,i) => { d.fit(a(i)) }) // apply fit to each array (d)
  .flatten() // put them back to single dimension if needed
taylorbf commented 7 years ago

Thanks Taka. Your first examples are interesting and I think could lead to some nice compositional possibilities.

The second example is too verbose for my current application (live coding), and that gets to the source of the issue -- trying to find ways to fit the awesome capabilities of dtm into short phrases. Perhaps too short. ; )

Don't feel like you need to bend the library design for these concerns. Thanks for your thoughts!