Git Product home page Git Product logo

Comments (26)

magnetophon avatar magnetophon commented on August 23, 2024 1

Thanks to @rulatir for the music links, I'm blown away by Eden Kesete!
Thans to @sjaehn for the quick implementation, even if just the more simple variant.

from bschaffl.

sjaehn avatar sjaehn commented on August 23, 2024 1

"sequence(s)" and "step(s)" just pushed to master.

from bschaffl.

rulatir avatar rulatir commented on August 23, 2024 1

Absolutely! I'll fork and PR a declaration of a utility class, and once we settle on the interface, I'll implement it.

from bschaffl.

sjaehn avatar sjaehn commented on August 23, 2024 1

You will not get in touch with the realtime and lv2 special stuff. So no need to worry about. Only the plugin specific thing: Do not use external libraries which need to be linked dynamically. But the C++ standard libraries are fine.

from bschaffl.

magnetophon avatar magnetophon commented on August 23, 2024

I'm not sure I understand correctly:
In your example, you'd enter 5 midi eighth notes in your daw, and you'd hear a pattern of:
eighth, quarter, eighth, quarter, quarter.
That seems like a very confusing way to write music, no?

from bschaffl.

rulatir avatar rulatir commented on August 23, 2024

eighth, quarter, eighth, quarter, quarter

That's what I would hear if STEPS PROCESS were set to 1.0, but it wouldn't be set to 1.0! The numbers would only specify the "inflection pattern" or "swing pattern" or "groove vector" depending on your terminology. With STEPS PROCESS=1, the pulse onset times would indeed be:

[0.0, 0.125, 0.375, 0.5, 0.75]

which is exactly equivalent to eighth, quarter, eighth, quarter, quarter. But with STEPS PROCESS<1 the onset times would be interpolated between that and [0.0, 0.2, 0.4, 0.6, 0.8], i.e. the even 5/8. What is important musically here is that no matter how much groove is applied, certain relationships among durations are preserved:

  • the contractions of the first and third pulse are identical; while the unswung rhythm says |:ti-ti-ti-ti-ka|ti-ti-ti-ti-ka:|, the swung rhythm says |:tiri-tiri-ka|tiri-tiri-ka:|, and both "tiri" are equally contracted / flamified
  • another drum part says |:tan-*-tan-*-pe|*-*-pe-*-*:|, and the "tan-tan-pe" arc consists of three notes that remain exactly evenly spaced no matter how strong the groove
  • still another drum part says |:tum-*-kuRI-KI|TIN-*-*-*-*:|, and again, the RI-KI-TIN arc consists of three notes that remain exactly evenly spaced no matter the groove strength
  • there are always exactly two distinct effective rhythm values - "short" and "long" pulses; all the bullet points above are actually a consequence of this and the specific pulse contraction/expansion pattern: short-long-short-long-long, or [1,2,1,2,2].

I am working in a musical system in which combinations of groove constraints like the above are explicitly part of the musical form; doing too much or to little contraction on a particular pulse, or doing two different contractions on two pulses that should have the same amount of contraction, is as much of an error as playing a melody in the minor scale instead of major. I could achieve this accuracy in this particular instance if I could set the four inner sliders exactly to these pulse onset times:

[0.125, 0.375, 0.5, 0.75]

This is nearly impossible with current UI. I would be mostly happy if I could just enter those values numerically instead of pixel-hunting the right position of the sliders without realtime feedback. But why not go further and allow expressing the same intention with integers?

from bschaffl.

magnetophon avatar magnetophon commented on August 23, 2024

Thanks for your clear description.
It inspired a song!

Did I understand correctly?
Out of interest: could you link me to a song that is in the form you described?

from bschaffl.

sjaehn avatar sjaehn commented on August 23, 2024

Good idea. I think I understand your intention from your initial post. I already thought about the problem / impossibility to perfectly place the horizontally draggable markers. I had the idea to add a grid and allow the markers to snap to this grid. You can achieve similar results in the shape mode (the switch above "# 1"). Another option would be to enable direct entering of marker values. Then you can set 0.125 or the first one, 0.375 for the second one, and so on. I think this is what you like to get.

from bschaffl.

rulatir avatar rulatir commented on August 23, 2024

Firstly, my use cases are more in the /16s, we're talking about microtiming in the rapid common-measure pulse in a polyrhythm, rather than eighths or quarters.

Accent-contraction system

West African djembe music features an accent-contraction system, where either the main pulse coinciding with the beat or the bell-marked pulse is contracted, and remaining pulses are expanded. This yields two kinds of ternary djembe rhythms, those that contract the first pulse and those that contract the second pulse - it's really like two musical scales, but in the realm of rhythm.

Central time

A ternary groove that uses 3 distinct durations is found in Hausa music of Nigeria. This silly song's groove has pulse length vector [6,5,4], but sometimes the first pulse gets split, and it's is not 3:3 nor 2:4, it's something in between. You can multiply all the durations by 2 and then split the first 12 to 5+7: [5,7,10,8]. This groove (either with or without the 1st pulse subdivision) is not expressible in the "plain" accent-contraction system that only permits two pulse lengths, but accent-contraction system can express a groove that has some salient features of this groove.

Other sporadic rhythms

Guayla music from Eritrea and the Tigray region in Ethiopia is a quinary African groove that is neither accent-contraction nor central time but something else entirely. Here the pulse lengths are determined by a physical mechanism. The main accompanying instrument in this music is the krar, a simple lyre. Since there are two strumming directions (up and down), but five strums in a cycle, by mathematical necessity there must be two consecutive strums in the same direction somewhere: the hand must skip an up-stroke and instead hurry to repeat the down-motion again. This creates a "speed bump" in the motorics of playing, inducing a cascade of complex ebby-flowy rhythmic phenomena. And then comes an innovator like Tedalo who puts big speed bumps under the small speed bumps and drops a montuno-ish hook on top, because 3×5≈16 ;)

TL;DR

The world needs to be able to compute microtiming using many different mathematical models.

from bschaffl.

sjaehn avatar sjaehn commented on August 23, 2024

Idea: Add a third item called "Enter" to the popup menu which appears upon right click on a horizontal marker. Then enter a float value in the range [0, 1]. This should be easy to implement as my B.Widgets toolkit has got all tools needed.

And if I have much time for programming, then I can think about parsing expressions like "5/16" to 0.3125.

Important note: All values entered have to be transferred to relative values within the range [0, 1]. Due to compatibility. Thus storing values like [1,2,1,2,2] is not possible.

from bschaffl.

sjaehn avatar sjaehn commented on August 23, 2024

Something like this ?
Bildschirmfoto von 2022-06-20 22-47-53

... just pushed to the main branch.

from bschaffl.

rulatir avatar rulatir commented on August 23, 2024

Yes, that's a good level 1 implementation in that it makes what was entirely impossible possible, however if you want to encode [1,2,2,1,2], you must calculate the onset times in a spreadsheet or something.

It would be nice however to include a calculator for this, where you could enter 1,2,2,1,2 and populate all sliders with calculated onset times - that would be level 2.

For level 3 you could even pre-populate the calculator inputs with integer values computed back from the onset times. If the onset times were previously calculated from a relative durations vector that adds up to a sufficiently small common denominator, it is possible to recover that vector exactly. I know the math and can contribute C++ code if necessary.

For level 4 you could offer several approximations if the perfect match is impossible.The calculator dialog would have an "Approximate current groove" button that would show a list of several good approximations, sorted by some tradeoff between common denominator and actual accuracy achieved. If we cap the denominator at say 1024, it wouldn't be too expensive computationally to just generate the approximations for all denominators <=1024, then show a deduplicated list of best approximations in each denominator interval between the number of pulses and a power of 2 up to 1024... at most 10 candidates, and as few as 1 if there is a perfect match. I can contribute C++ math for that too.

At every implementation level, it would be nice to be able to export (copy to clipboard?) the list of onset times for tweaking with an external calculator (like a spreadsheet).

from bschaffl.

sjaehn avatar sjaehn commented on August 23, 2024

Thanks for your feedback. Indeed the option to enter the relative position is "only" level 1. It was rather easy to implement as I wrote before.

Level 1.1 would be an option to enter relative pulse lengths. Like "0.0625" for a 1/16 note. Also easy to implement.

The next level(s) would get complicated as I mentioned before. The problem: All marker positions are stored as relative positions in control ports with values of the range 0.0 to 1.0. Like here: https://github.com/sjaehn/BSchaffl/blob/master/BSchaffl.ttl#L481-L487

The nice thing: you can automate the marker positions in the host (e. g., your DAW). (Note: The plugin will only accept valid values, this means: x[i] >= 0.0; x[i] >= x[i - 1]; x[i] <= x[i + 1]; x[i] <= 1.0.) But you can't store any absolute values there. Especially if they are higher than 1.0. This would violate the plugin definition and thus the compatibility.

But there are some possible solutions for this problem:

Solution 1:
We need 16 additional control ports. The first will be a switch if relative or absolute values are used. And the ports 2 to 16 will contain absolute values. If the switch is set to relative values, then the control ports 45 to 59 and thus the relative positions are used. If the switch is set to absolute values, the 15 new control ports for absolute values are used. The relative position to be displayed is then calculated by the absolute position divided by the sum of the absolute pulse lengths.
Then it's possible to assign markers with values of 1, 2, 2, 1, 2 (sum 8) and they will be displayed as 1/8th, 2/8th, 2/8th, 1/8th, and 2/8th of the total sequence, respectively.
But now the problems: There is no way to convert to the relative position control ports 45 to 59 if you switch back to relative values. As LV2 control ports (which I used) are read only (unless you do it via the UI but this is error-prone and should be omitted)!
The second problem is automation. Once switched the mode, you stop the respective automation. Confusing!
This solution is a bit hacky and may results in conflicts. Therefore I don't like it.

Solution 2:
Add an option to enter absolute positions and/or absolute pulse lengths. The values entered are immediately used to calculate relative positions by dividing by the number of steps (port 10) and the result is stored in the control ports 45 to 59.
So you can again assign markers with values of 1, 2, 2, 1, 2. But now not the sum is used but the number of steps. In the case of the default of 16 steps it will be displayed as 1/16th, 2/16th, 2/16th, 1/16th, and 2/16th of the total sequence, respectively. But this can be the intended way, too. And the more intuitive way for me.
Automation still works, no conflicts, no compatibility issues as the plugin description doesn't need to be changed. And much easier to implement!
No solution without problems. If you change the numbers of steps afterwards, then you "loose" the absolute numbers. But you keep the proportions. A change from 16 steps to 8 steps would result in a pattern of 0.5, 1, 1, 0.5, 1.

In conclusion, I'd prefer the solution 2. You too? Or any other solutions? This would be level 2, I think.

PS: Even level 3 shouldn't be that hard to realize.

from bschaffl.

rulatir avatar rulatir commented on August 23, 2024

All use cases that I envision involve using Integer Relative Pulse Lengths as a convenient manual input method only, i.e. as a shortcut method to set the sliders to positions calculated using a particular simple mathematical model. Everything about storing those positions and recording them onto automation lanes should stay as is. The integer values entered by the user in a hypothetical IRPL input would only exist in the UI, and transiently so, i.e. until the user commits the UI, at which point they would be converted to the standard representation. Typically one would use the IRPL input method once to store initial values at the start of the song or a song fragment, at the same spot(s) where the time signature is set or changed. Then you would only use the STEPS PROCESS control to vary the intensity of the grove, or otherwise use the sliders as usual. Further levels I proposed would just be convenience tools to calculate an approximate IRPL representation of a groove that was previously defined with sliders, slidered away from a low-denominator rational point in the pulse lengths space, or even measured from a recording. Those features however could probably be moved to an external online companion tool, as they would be used less frequently, and certainly never in a live performance.

from bschaffl.

rulatir avatar rulatir commented on August 23, 2024

I'm worried about the scenario where the number of pulses gets changed via automation. Is it currently supported? How? Do you resample the inverse time map, or do you truncate (if the number of pulses is decreased) / fill with even pulses (if the number is increased)? I propose that the IRPL input would require entering exactly as many values as there are pulses. Whatever happens currently to the pulse positions when you change the number of pulses, they ultimately represent some new continuous map t → t' for 0 < t < 1, and when you invoke the IRPL input again, it would (at my level 4) offer approximations of that new map using the new number of pulses.

TL;DR - the IRPL UI that I would like to have would be just a "groove picker" - you wouldn't store its UI-oriented representation in the song, just as you would only store the RGB triple and not a screenshot of the color picker ;)

from bschaffl.

sjaehn avatar sjaehn commented on August 23, 2024

Step by step I understand where you want to go.

  1. Enter Integer* Relative Pulse Lengths (IRPLs) to calculate and store the relative pulse lengths (0.0 to 1.0). This is nicely compatible with the solution 2. And easy to implement.

  2. The number of steps is realized as a control port. Like almost everything in the plugin with the notable exception of nodes in the shape editor. Thus the number of steps can be automated by the DAW. You may think about if it makes sense or not. But it shouldn't hurt. Relative pulse lengths (0.0 to 1.0) stay the same if you change the number of steps. 1/16 = 0.5/8 = 0.0625. Thus, no change in musical output if you change the number of steps (except the steps you cut away and the auto steps, of course). As long as you keep the sequence size. But this makes sense.

  3. Your level 3 would simply be to calculate back the IRPL from the relative pulse length (0.0 to 1.0) and the number of steps. Plus a simple rounding to integers. Level 4 can be realized by setting the number of steps to the lowest common denominator. No need to change the relative position of the markers, except rounding maybe.

  4. Groove picker can be implemented after all other ideas are implemented.

* I'm still open to also allow non-integer values here, maybe for a [1, 2, 2, 1.15, 1.85] groove.

from bschaffl.

rulatir avatar rulatir commented on August 23, 2024

I've got nothing against non-integer values in principle; I just want the summing and dividing by the sum and computing the running sums (relative times) done for me.

I now understand that there is no recomputation happening when the number of steps is changed. If I start with 16 steps and switch the first marker to manual and then reduce the number of steps to 2, the first pulse will still be 1/16th of the whole cycle and the remaining pulse will be stretched to fill. I disagree that this amounts to "no change to musical output" ;) but I agree that it makes sense, because automation controls must be independent; it's on the user to make sure that the settings make musical sense.

Re. 3, optimal recovery of the IRPL is not that simple, but it's doable.

from bschaffl.

sjaehn avatar sjaehn commented on August 23, 2024

Draft:
Bildschirmfoto von 2022-06-23 18-42-13

I replaced the "New position" label by a menu to select between "New position" and "New length". I also added a menu to choose between "sequences" (range 0.0 to 1.0) and "steps" (range 0 to number of steps).

from bschaffl.

sjaehn avatar sjaehn commented on August 23, 2024

The next step is done. I pushed a few additions to the master branch. Now you can enter and apply new step lengths with integer (or float) values.

from bschaffl.

rulatir avatar rulatir commented on August 23, 2024

I may by nitpicking, but the "sequences" vs "steps" language is not super clear to me, particularly "sequences". I understand (with effort) that you mean the whole sequence of steps, used as a unit. Even though it is nominally correct to use the unit name in the plural, in this case validation will never allow a value > 1, so plural is somewhat confusing here. Perhaps something like "in [sequence|step] units" would be clearer?

from bschaffl.

rulatir avatar rulatir commented on August 23, 2024

Anyways, huge thanks for this awesome plugin and the quick implementation of this feature request!

from bschaffl.

sjaehn avatar sjaehn commented on August 23, 2024

"Sequence" and "steps" are consistently used in the plugin ("Sequence size", "Number of steps", "Steps swing", ...). There is a definition of the term "sequence" in music theory. This definition is valid here too (and it makes sense), but you aren't tied to it. The terms "sequence" and "steps" make even more sense if you think about step sequencers (the name!) and their definition of "steps" and "sequence" there.

About the use of the plural. It would also be right for values < 1! Like 0.5 sequences (like 0.5 kilometers). But I agree, I should write "sequence(s)" and "step(s)" to cover all cases.

from bschaffl.

sjaehn avatar sjaehn commented on August 23, 2024

@rulatir, as level 3 is done by now (OK, rounding is still open, but by now I think it isn't that important), may I now come back to your offer to contribute C++ math for current groove approximation?

from bschaffl.

rulatir avatar rulatir commented on August 23, 2024

I've never coded for lv2 though. Anything I should be aware of?

from bschaffl.

rulatir avatar rulatir commented on August 23, 2024

Can we pass std::vector<>s around, or do you want it C-style where you pass me buffer pointers and sizes?

from bschaffl.

sjaehn avatar sjaehn commented on August 23, 2024

I'd clearly prefer vectors.

from bschaffl.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.