notator / WebMIDISynthHost

Hosts software Web MIDI Synths that implement a superset of the Web MIDI API Output Device interface.
Other
18 stars 3 forks source link

ResidentSf2Synth: Note Velocity #29

Open notator opened 7 years ago

notator commented 7 years ago

February 2016: Currently, note velocity always affects outputGain as follows (in soundFontSynthNote.js):

outputGain.linearRampToValueAtTime(this.volume * (this.velocity / 127), volAttack);

Account should be taken of parameters (Substitution Generators) defined in the sf2 file. See sfspec24.pdf §8.1.1, §8.1.2, §8.2.1, §8.4.1 and §8.4.2.

Edit March 2016: I have now changed the way MIDI velocities are handled: Gain now changes exponentially with velocity. The above code has changed to

velocityFactor = (this.velocity / 127) * (this.velocity / 127); 
outputGain.linearRampToValueAtTime(this.volume * velocityFactor, volAttack);

This gets much closer (maybe is identical to?) the way velocity is handled by other online MIDI synths such as the Virtual MIDI Synth and the Microsoft GS Wavetable Synth. After this change, Study 1 (played on this synth in the Assistant Performer) sounds much more like the original recordings made with capella and Moritz. See http://james-ingram-act-two.de/compositions/study1/study1.html.

timjrd commented 7 years ago

Hi :)

I can't find velocityFactor in soundFontSynthNote.js, is this the correct version ?

I have a side issue with velocity: when I fire a noteOn, the velocity is not taken into account. I did a quick fix by replacing this line (#132):

outputGain.linearRampToValueAtTime(this.volume * (1 - instrument.volSustain), volDecay);

by this line:

outputGain.linearRampToValueAtTime(this.volume * (this.velocity / 127) * (1 - instrument.volSustain), volDecay);

But I don't know if it's correct.

notator commented 7 years ago

Thanks very much for your interest in this code, and for the suggestions! Sorry about the delay, but I've been away.

The missing velocityFactor

I remember removing the exponential response to velocity again, but forgot to update this issue. I made the response linear again because the quietest volumes are inaudible in Arachno Preset 0 (Grand Piano) when the response is exponential.

Nevertheless, I've now made the response exponential again, and the result sounds very similar to my reference Synth (the VirtualMIDISynth). (Listen to the perceived volume of the ppp chords in Study 1, staves 30-33 on both Synths in the Assistant Performer, and to the inaudible GrandPiano velocity 1 in the WebMIDISynthHost). According to the MIDI spec, synths are free to respond to velocity in any way they like, but an exponential response is the default:

Interpretation of the Velocity byte is left up to the receiving instrument. [...] Preferably, application of velocity to volume should be an exponential function. This is the suggested default action [...]

But the spec also says;

note that an instrument may have multiple tables for mapping MIDI velocity to internal velocity response.

So I suspect that this is not the final answer to this issue. As I said at the top of this thread:

Account should be taken of parameters (Substitution Generators) defined in the sf2 file. See sfspec24.pdf §8.1.1, §8.1.2, §8.2.1, §8.4.1 and §8.4.2.

volSustain

I think you are right, that the sustain value should be related to the volume level used in the previous line, so I've updated the file accordingly. As far as I can tell, this makes no difference in the ResidentSf2Synth when using the Arachno SoundFont. (tested using the WebMIDISynthHost). It would help a lot if you could test this change using your soundFont. Again, I think the reason that our soundfonts are responding differently is that the synth is ignoring some relevant parameters that are defined differently in the two fonts.

The AssistantPerformer and the WebMIDISynthHost use different copies of the ResidentSf2Synth. I've updated both to the latest version in this repository.

Thanks again for helping to improve this code!