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

Volume curve #53

Open
chriscoomber opened this issue Jan 6, 2021 · 2 comments
Open

Volume curve #53

chriscoomber opened this issue Jan 6, 2021 · 2 comments

Comments

@chriscoomber
Copy link

chriscoomber commented Jan 6, 2021

I've been looking into volume curves recently, because my implementation of a MIDI player using TSF didn't sound quite right. In the end I was using a linear curve to map MIDI velocity (0-127) to the velocity (0-1) in tsf_note_on. It turns out that a quadratic curve is a better fit.

This led me to do some maths that a) I'd like to share in case anyone else is worrying about this, and b) I think it would be useful to use a quadratic curve in your examples (e.g. here), and also here.

A MIDI note has a velocity v between 0 and 127 (int).
TSF asks for a velocity x between 0 and 1 (float).
In the final output, we get a volume L measured in decibels between -∞ and 0 (this is the difference in decibels from full volume, i.e. 0dB is full volume).

According to the GM recommendations (bottom of page 9) the recommendation is to map between v and L by L = 40 log (v/127).

From looking at TSF's code, it maps between x and L by L = 20 log (x) (see tsf_gainToDecibels).

It's the user of TSF's job to implement the map between v and x. If we want to conform to the GM recommendations, we need 40 log (v/127) = 20 log (x), i.e. x = (v/127)^2.

Therefore, I recommend that people using TSF use the mapping x = (v/127)^2 when calling tsf_note_on or similar functions. It makes sense to me to default to conforming to the GM recommendations.

I think it would be good to update the examples to use this map, rather than x = v/127 (which I see in example3.c). Also, I wonder if you should use a quadratic map rather than the cubic map x = (v/16383)^3 in TCMC_SET_VOLUME (here v is between 0 and 16383).

@schellingb
Copy link
Owner

Whoa, thank you so much for this post.

The comment in TMC_SET_VOLUME

//Raising to the power of 3 seems to result in a decent sounding volume curve for MIDI

explains about how much my understanding of this is.

Your description makes a lot of sense though and I'll happily incorporate your recommendations.

To verify things a bit, what do you think would be a good test MIDI to generate, and against what player should we compare?
For example:

  • 1 second sawtooth at 127 velocity followed 1 second at 64, then a control message VOLUME_MSB to 50% and the same notes again
  • Then export the generated 4 second PCM to a WAV from TSF and bass midi or fluidsynth.
  • Compare the generated audio waves

@chriscoomber
Copy link
Author

Honestly my knowledge yesterday is about what yours is. All I did was by ear compare some simple piano notes of different velocities against the stock Android MIDI player, which is far from thorough. I found that the quadratic curve seems to match the stock Android MIDI player the best, and I think the maths explains why. I did find I needed to boost the global volume a little in tsf_set_output as well, to match that particular MIDI player (I settled on about 15dB). I haven't tested against other MIDI players though.

Your suggestion sounds sensible, I think that's about all I can contribute though.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants