Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Kbm support #329

Open
baconpaul opened this issue Jul 24, 2020 · 23 comments
Open

Kbm support #329

baconpaul opened this issue Jul 24, 2020 · 23 comments
Labels
new feature Feature additions and requests
Milestone

Comments

@baconpaul
Copy link

Hi! Thanks so much for integrating our tuning library!

I see you added only the scl file support in 0.4.0. Is it possible to also add kbm support? It has proven important in several contexts and the support is complete in our lib (just use the two argument constructor form and parse the kbm using the same interface). Having a sampler with full scl/kbm support would be fantastic!

Oh also I see you copied the lib and made a couple of changes. If those are logic changes happy to merge them back

Best

@paulfd paulfd added this to the 0.4.1 milestone Jul 24, 2020
@paulfd
Copy link
Member

paulfd commented Jul 24, 2020

Hi! Well @jpcima is the artist in this 🙂 We can look into this quickly; as you said everything's there it's more a matter of UX and integration.

@jpcima
Copy link
Collaborator

jpcima commented Jul 24, 2020

Hello,

I see you added only the scl file support in 0.4.0. Is it possible to also add kbm support?

An idea in the current software was to imitate tuning feature as found in some commercial software out there.
There is one of the software which supports SCL only, and the other more elaborate one has tuning according to this parameter set:

  • scala file
  • scala root note
  • reference frequency (440)
  • stretched tuning

This is what we're implementing currently, but this model is conflicting with KBM, it's either one or the other.
KBM is not out of the question, but then it needs some sort of switch, either use the simplified model or KBM file.

Oh also I see you copied the lib and made a couple of changes. If those are logic changes happy to merge them back

This is correct, this changes were written a bit ago. I wish to contribute the work back upstream, but it's not complete entirely in a way I'd like it, and there is tons of other work to do beside this. I adapted only to cover sfizz's use cases.

For short, the requirement was being able to recalculate the tuning in RT context, and also I think we need copies.
That means avoidance of such things as std::istream, std::string and friends.
The API tuneNoteTo does not have this ability in the upstream implementation.

In this regard I worked around a number of dynamic allocations in the lib, but this is not a complete work, only to meet current sfizz requirements.

PS of course, thanks very much for this library :)

@baconpaul
Copy link
Author

So I provide functions in the tuning library to make a kbm file which sets the reference frequency and root notes. What I did in surge was provide those functions by generating a kbm and then using that kbm. Or allow a user to load a kbm directly and override. Can that work here?

Kbm are particularly useful complete spec both for root note and frequency but also for non uniform keyboards (one of our surge users is mapping to an axis controller for instance). I think many synths make a mistake as thinking of kbm as optional as opposed to integral actually, which is why we made those utility functions part of the lib.

Lemme know if you need any help! Would love to help out

@jpcima
Copy link
Collaborator

jpcima commented Jul 24, 2020

Really the sfizz logic creates a virtual KBM based on the reduced set of parameters and it's nothing very special. For reference

sfizz/src/sfizz/Tuning.cpp

Lines 140 to 151 in fe4e5ff

Tunings::KeyboardMapping Tuning::Impl::mappingFromParameters(int rootKey, float tuningFrequency)
{
#if 1
// root note is the start of octave. like Scala
#else
// root note is the start of next octave. like Sforzando
rootKey = std::max(0, rootKey - 12);
#endif
// fixed frequency of the root note
const double rootFrequency = tuningFrequency * std::exp2((rootKey - 69) / 12.0);
return Tunings::tuneNoteTo(rootKey, rootFrequency);
}

KBM files can be used in substitution to this, it's not a big issue as logic is concerned.
Integration in API is fine, but plugin is another thing.

@baconpaul if I may ask something absolutely unrelated, your loading code of WAV & WT wavetables seems remarkably useful, would this code be considered for being published as library in the future?

@baconpaul
Copy link
Author

Oh cool so you already use the keyboard mapping class in a fizz? Then yeah it is just ui!

Oh right the “find all the tags of every wav file because libsndfile doesn’t give you blocks” code? I suppose I could factor that yeah. Are you gpl3? Happy for you to just copy it too. I think I’m the only author on that file so I could drop it into an mit submodule if so though. Is that what you’re thinking?

@jpcima
Copy link
Collaborator

jpcima commented Jul 24, 2020

I think I’m the only author on that file so I could drop it into an mit submodule if so though. Is that what you’re thinking?

Something like this, yes. This question arises as I'm about to introduce basic support of multi-wavetables.
Surge comes up as the best resource when I searching for references of wavetables formats, and I found it has already a varied support of formats (Serum, NI, WT and such).
This would be helpful for this code to be reusable, which I just wanted to make it known :)
otherwise yes, the starting idea is that I use Surge as a reference and reimplement our own as non-GPL.

@jpcima
Copy link
Collaborator

jpcima commented Jul 24, 2020

I opened #330 , let's rather discuss the matter over there

@paulfd paulfd modified the milestones: 0.4.1, 0.5.0, 0.6.0 Sep 22, 2020
@paulfd paulfd added the new feature Feature additions and requests label Mar 9, 2021
@baconpaul
Copy link
Author

Hi @jpcima

just kicking this one a bit.

 // fixed frequency of the root note    
const double rootFrequency = tuningFrequency * std::exp2((rootKey - 69) / 12.0);   
 return Tunings::tuneNoteTo(rootKey, rootFrequency);

this code doesn't actually work for a wide variety of scales - it assumes that the root key is 12tet away but it usually not. So in this case, if you had, say ED2-19 you would tune C to 261 but that would not leave A tuned to 440.

If instead you use

https://github.com/surge-synthesizer/tuning-library/blob/46a58f87e880d70ece0b015e1ef59fbfdc14dea9/include/Tunings.h#L203

you can get the correct tuning adjustment. In your case it would be to modify the above code to

return Tunings:: startScaleOnAndTuneNoteTo(rootKey, 69, rootFrequency);

then it will give you at least tunings that match your UI! (Full KBM file support would be even better though).

@jpcima
Copy link
Collaborator

jpcima commented May 17, 2021

Thanks for the tip. From old memory, I have tried this one, but then went for the custom formula.
It was for matching Sforzando's tuning model, which is our reference software.
I checked 1-on-1 on a ton of scale files and parameters.
With that being said, I would not mind too much changing to a model which makes more sense.

@baconpaul
Copy link
Author

baconpaul commented May 17, 2021

If you load ed2-09and use root key of c your call will set note 60 to 261hz - the 12 tet walk down from note 69. But then if you play note 69 it will be an octave up so 512hz not 440

If you use the 3 key api you will get note 69 tuned to 440 and then with ed2 09 will get note 60 tuned to 220

so I guess in the case of a 9 note even scale where the reference note is 69@440 what do you want middle c/60 to be? And what do you want 69/a4 to be?

I think you want 220 and 440 yeah?

@jpcima
Copy link
Collaborator

jpcima commented May 18, 2021

I can't tell yet, need to put some focus back into this.
just a few things:

  • it's nearly identical to what sforzando software does, but this behavior might be buggy / not a good reference
  • the retuning is not a part of the SFZ specification itself, so we don't have an obligation to stick that method
  • the interactions between tuning and various SFZ behavior can be put in question;
    for example, should keyboard remapping affect key-ranges of regions?
    in our case, it doesn't (and neither do other impls I believe), but this may result of samples being way off their intended frequency range.

@alcomposer
Copy link
Collaborator

should keyboard remapping affect key-ranges of regions?

I think this is a valid point, given that SCL, KBD, and MTS can radically change the number of notes in an octave (or even octave relationships)

This is why some software (eg Logic Pro) lock any tuning to 12 notes per octave SCL files. As too many instruments would break otherwise.

However, given that the SFZ script defines an instrument, having a Scala opcode may be a safe way to move forward for tuning files that are not based on 12 tones.

Thus the instrument itself can be defined with a tuning. We could allow the built in tuning the freedom to express any tuning possible.

The sfizz tuning preference would be locked to the number of intervals in the SFZ script opcode.

This would work 1:1 with region definitions, but also alow instrument makers the ability to build unique instruments, without the restrictions of a Western cultural music framework.

This solution would unfortunately limit sfizz to using SCL exclusively, as SCL is able to define the intention of the scales range‡

Alternately, we accept that any tuning outside of 12t could break region relationships. But I don't know if this solves the adjacent issue of being able to define an instrument with a tuning.

‡ I'm aware that SCL files are able to express non-octave scales. There would still be ways of breaking this system, this only makes it a bit harder.

@baconpaul
Copy link
Author

Pianotec and surge are good reference impls here to see if you are tuned. But they jut do what the tuning library does. I do t have an opinion on key range stuff but I do know that the 12 tet walk down will break your tuning. At least change the api point to the 3 argument version with 69 hardcoded will make sure that when you do use scales which are both not 12 long and where the distance between the root note and note 69 is not distance * 100 cents (which is lots and lots of scales) you will get the right tuning? If sforzando does the 12 trt walk-down it is wrong though in that if you tune note 69 to 440 using the method you have many scales will, have 69 not be 440.

But ideally let users supply a KBM seems to be the answer no?

@alcomposer
Copy link
Collaborator

alcomposer commented May 19, 2021

Pianotec and surge are good reference impls

Remeber that both use synthesis predominantly. While sfizz has both, with a much greater focus on sampling.

I'm very interested in sfizz inhabiting both spaces, and being used for hybrid as well.

However due to the usage of key ranges and switches, a tuning solution needs to allow the system to function.

At the end of the day I think the important thing is supporting tuning, and allowing people to develop instruments that are expressive.

If that is using SCL, KBD, MTS or something else is irrelevant.

It could very well be that advanced tunings are better suited to be placed in a scala opcode. So that the tuning is embedded into the instrument, (or at least the general concept of intervals)

There is a big difference between swapping tunings for 12t and 5t, or even systems that lack octaves.

@baconpaul
Copy link
Author

Yes I understand that. I just meant Pianotec and surge are good references for “this key has this frequency”, which is really all I’m talking about. And which the 30 character change I’m proposing to the code would mean sfizz does correctly.

Tuning in samplers is hard. But setting note 69 to 432 in your ui and have it not be 432 is also probably not what you want :)

@baconpaul
Copy link
Author

Btw a scale scl and kbm op code in sfz is a good idea! In surge we have options for patches to store tunings and mappings for this exact reason and in sampler contexts it is even more important.

@paulfd paulfd modified the milestones: 0.6.0, 1.1.0 May 24, 2021
@paulfd paulfd modified the milestones: 1.1.0, 1.2.0 Jul 20, 2021
@paulfd paulfd removed this from the 1.2.0 milestone Nov 10, 2021
@baconpaul
Copy link
Author

Hey folks!

any chance you could look at this again? It’s a real easy change

also in the last year I fixed some edge case bugs in tuning lib so you may want to pull even if you leave the mapping wrong!

@paulfd paulfd added this to the 1.2.1 milestone Mar 31, 2022
@paulfd
Copy link
Member

paulfd commented Mar 31, 2022

I'll put the simple change in the upcoming release if I find a little bit of time, also as a test to see if anyone actually complains about the differing behavior with sforzando.

@baconpaul
Copy link
Author

Awesome thank you!

It is relatively easy to replicate the sforzando behavior if you really want - namely you just tune note 60 to that frequency from the formula. But indeed if someone sets note 69 to 440, and gets 412, and thinks that is correct, then they will complain!

For sampled instruments most scales have length 12 and are tiny tweaks anyway so the difference will really just be the cents knocked out from C to A vs concert.

@Andreya-Autumn
Copy link

Hey everyone! Just wanted to pop in and say, me and a few others would be glad to see this change implemented. There's currently no free sampler that handles tuning adequately, and it would be great if one existed! :)

@Andreya-Autumn
Copy link

One thing that I do want to add. About the keyranges and regions.

One of the things that's so great about correct kbm implementation (and also about MTS-ESP, but that's another issue) is that it lets you un-map keys. So for the 9-note scale in Pauls example, you might choose three notes and make them un-mapped. Pressing those keys would then result in silence, and the actual doubling of frequencies takes up the same amount of keys as normal. So at least for scales with <12 notes, this change may actually help avoid problems with key ranges when retuning.

Scales with >12 notes, and especially alternative controllers, might take some more thought to get right for the key ranges. But it's at least a start!

And just as a point of possible interest: Several folks I know have been expressing their disappointment at Sforzandos tuning features. So I'd like to humbly suggest that when it comes to tuning in particular, feature-parity with Sforzando might not be a good goal.

Thanks for your time!

@XaviP
Copy link

XaviP commented Jan 17, 2023

I join kbm support proposal. Many LV2 plugins are working with kbm&scl: zynaddsubfx, surge, synthv1, samplv1, amsynth,... It's becomming popular. See, for example, this blog post from sevish. Thanks for this marvelous software.

@redtide redtide modified the milestones: 1.2.1, 1.3.0 Apr 13, 2023
@tank-trax
Copy link

tank-trax commented Aug 4, 2023

KBM support would be great, however with the current setup Frequency can only be between 300.0 Hz and 500.0 Hz

As much as many people use A4 at 440.0 Hz many microtonal musicians prefer to use C4 at 261.6 Hz (having extra decimals would also be useful) which is not possible with the current build

Could you make it that the range for Frequency be greater than 300-500 Hz? At least allowing for 200 as bottom limit would ensure that C3 at 261.6 is feasible.

EDIT:

It appears the SCL file was not loaded likely because of it's location having moved. Once reloaded the A4 setting to the assigned frequency corrected an issue I was facing. Having an extra decimal place or two would still be a nice addition.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
new feature Feature additions and requests
Projects
None yet
Development

No branches or pull requests

8 participants