This fixes a regression introduced in 907ec27a9e
When rendering a voice, there are 3 cases to consider: silent, playing,
and finished. When optimizing away the memset, I incorrectly assumed that
a voice cannot switch between playing and silence (like crazy) while
rendering FLUID_MIXER_MAX_BUFFERS_DEFAULT. Apparently this does not
hold true, esp. when rendering at sample rates ~96kHz.
This adds new LFO modulators:
- these modulators are computed on the fly, instead of using lfo lookup table. Advantages:
- Avoiding a lost of 608272 memory bytes when lfo speed is low (0.3Hz).
- Allows to diminish the lfo speed lower limit to 0.1Hz instead of 0.3Hz.
A speed of 0.1 is interesting for chorus. Using a lookup table for 0.1Hz
would require too much memory (1824816 bytes).
- Make use of first-order all-pass interpolator instead of bandlimited interpolation.
- Although lfo modulator is computed on the fly, cpu load is lower than using
lfo lookup table with bandlimited interpolator.
Also adds a stereo unit controlled by WIDTH macro. WIDTH [0..10] value define a stereo separation between left and right.
- When 0, the output is monophonic.
- When > 0 , the output is stereophonic.
WIDTH is currently fixed to maximum value to provide maximum stereo effect.
`GTimeVal` has been deprecated in glib 2.62 . While switching to `g_get_monotonic_time()`, I realized that we could simply reuse `fluid_utime()` for that purpose.
This provides a less branchy and therefore more instruction-cache-friendly version of fluid_ct2hz(), which also significantly reduces the number of floating-point comparisons.
- memset should clear all the memory
- end position should be at the end of sample data
Closes#576
Signed-off-by: Stefan Westerfeld <stefan@space.twc.de>
The synthesizer is using stdint types for a long time, perhaps for consistency, it would be worth to get rid of the GLIB macros for integer to pointer conversion and viceversa, and use just a type cast for that purpose.
The parameters (roomsize, level, etc.) of the reverb effects unit are initialized at the very end of `new_fluid_synth()` with `fluid_synth_set_reverb_full_LOCAL()`.
This however only adds an update-event to the `rvoice_mixer` queue.
The call to `fluid_synth_process_event_queue()` in `new_fluid_synth()` should make sure, that this event is dispatched and triggers the actual update.
However, the event is not dispatched immediately, because the rvoice event queue has not been committed yet, that is, a call to `fluid_rvoice_eventhandler_flush()` is missing.
So, although a reverb param initialization event has been queued, the reverb params still are garbage initialized (on Windows to some `-6.2774385622041925e+66`).
The next call to through the synth's public API will flush the queue and finally dispatch the update event, but when will it happen?
1. If the soundfont is specified as command-line argument, this call will happen before the audio driver starts rendering.
2. If the soundfont is loaded via shell command `load`, the audio driver will first start rendering audio, after updating the reverb.
Case 1. is trivial, everything works as it should.
Case 2. is interesting. Since the synth already started rendering audio by using that uninitialized reverb unit, the reverb engine's internal buffer is completely filled up with noise. Before outputting that signal to sound card, the sound is clipped to `1.0f`. That's the click we hear at the beginning. And because the reverb is so loud, the rendered audio signal stays 1.0f for quite a long time (...or always, can't tell).
Why is it not reproducible on Linux? Because GCC and Clang (AFAIK) leave all values uninitialized after allocating memory. And because malloc() often return zero-initialized memory, the reverb params seem to be nicely zero-initialized. MSVC however, always initializes memory with garbage, which is why we "hear" this resonance disaster.
Solution: Just update the reverb params via public API, which implicitly calls `fluid_rvoice_eventhandler_flush()`.
Fixes#563.
Fixes a use-after-free when the MIDI player is deleted before the audio
driver, because the synthesis thread is still actively making callbacks
on the sample timer, which is deleted by the player though.
Enabling the option supresses the default welcome message and
some other text output that normally gets printed to stdout.
It also slightly changes the way the welcome message and argument
errors are handled: in case of an argument error, the welcome message
is never printed.
Previously, sample timers were deleted in fluid_player_stop() which caused a use-after-free when at the same time the sample timers were advanced by the synthesizer thread. This was incorrectly addressed in 5d3f727547 . Deleting sample timers is now done in delete_fluid_player(). A broken application could still crash if it does not respect the order of object creation though. At least now, this issue is properly documented.
In an out of memory situation, fluid_synth_t::voice and fluid_synth_t::channel may not be fully initialized, causing a NULL dereference and heap corruption in delete_fluid_synth().
By default, libinstpatch silently adds all SF2 default modulators to the
converted DLS voices. Since fluidsynth respects the modulators provided
by libinstpatch, those modulators would conflict with the default
modulator list managed by fluidsynth. This is only noticeable, if the
user used fluidsynth's API to manipulate default modulators.
When compiled with compatibility for WinXP (toolset v141_xp), read() may return 0 (EOF) rather than '\n' which led to an early exit of the shell after a single user input.
Vorbis compressed SF3 samples are always loaded individually and stored
in the sample cache in uncompressed form. When dynamic-sample-loading is
not active (the default), then the uncompressed samples did not get
unloaded when unloading the SF3 font.
This fix makes sure that those samples are also freed. For bulk loaded
samples, the sample->data pointer is always the same as the
font->sampledata pointer. For individually loaded samples, the sample->data
pointer always points to a different memory region. So we can use that
information to determine if and when to unload the samples one by one.
Fixes#530Fixes#528
The old buffering code assumes that synth->cur is between 0 and FLUID_BUFSIZE.
However since fluid_synth_process() can render more than one buffer at a time
this isn't always true, and the new code handles other values properly.
Closes#527
This set of changes implements audio drivers for Android, OpenSLES and Oboe. The changes in the original sources are kept minimal so that it should be easily maintained.
When fluidsynth is run as a service using systemd, make sure
the service is considered started only when it is ready to process events.
In order to do so:
- Add an optional runtime dependency to libsystemd to the fluidsynth executable
- Change the systemd service type to "notify"
- Have fluidsynth notify systemd that the service is started after the server is started
- Have fluidsynth notify systemd that the service is stopping after joining the server thread
possibly due to glibc-2.29 commit 424c4f60ed6190e2ea0e72e0873bf3ebcbbf5448
pow is using fused-multiply-add (fma) if available.
That caused the fluidsynth binaries to differ depending on
the build machine's CPU.
This was visible among others in
grep '7.58577575029183[56]e-04' fluidsynth-2.0.3/build/fluid_conv_tables.c
See https://reproducible-builds.org/ for why this is matters.
Closes#512.
-Name of an instrument zone shouldn't prefixed by the preset zone
name.
This is due to the fact that instrument zone are common to all
preset zone. Consequently, an instrument zone cannot identfied
via a preset zone.
-This new change, simply prefixe a zone as this:
instrument zone name prefixed by iz:
preset zone name prefixed by pz:
Normalized value of MIDI sources (before unipolar or bipolar mapping) is always in the range [0..+1], regardless of MIDI event (even for FLUID_MOD_PITCHWHEEL).
Actually some basic modulators check are done at noteon time (in fluid_voice_add_mod()). That means that we know if a modulator (modx) is invalid only when a MIDI noteon is received and only for a preset modx belongs to. This is not appropriate.
This moves the modulator checking at soundfont loading time. Enhancements are:
1) A better verbose modulator integrity check, for any soundfont loaded at appropriate time.
1.1) All modulators are checked (preset zone (local/global), instrument zone (local/global).
1.2.1) Modulators check are enforced to source src1 and src2 (for non-CC and CC sources) (following SF specs (except for CC LSB) ( see comment in fluid_synth_cc_LOCAL()).
Modulators CC sources checking is coherent with the actual behaviour in fluid_synth_cc_LOCAL() in regard of modulation triggering.
1.2.2) Also, identical modulator in the same zone are detected.
1.2.3) Any invalid modulator(sources invalid, or modulator identical) is removed at loading time with a warning message displaying the cause and name of the modulators.
2) This fix a bug in noteon, in the case of identical modulators in global preset zone.
Assuming 2 identical modulator (m1 and m2) in a preset global zone, the actual noteon doesn't check this case (the actual code detect identical modulator in all others zones (instrument (local or global), preset(local)) but not preset global).
3) NoteOn is faster.
3.1)There is no more modulators checks at noteon making this more efficient.
3.2) As there are no identical modulator in the same zone, there is no more identity modulator check (i.e local zone against local zone), (i.e global zone against global zone). This result in a faster code and the bug described in (2) is gone.
4) Modulators sources checking as been added in API functions fluid_synth_add_default_mod() and fluid_voice_add_mod(). Please
- When primary source input (src1) is set to General Controller
'No Controller', output will be forced to 0.0 at synthesis time
(see fluid_mod_get_value()).
That means that the minimum value of the modulator will be always 0.0.
We need to force amount value to 0 to ensure a correct evaluation of the
minimum value later (see fluid_voice_get_lower_boundary_for_attenuation()).
- When secondary source input (src2) is set to General
Controller 'No Controller', output will be forced to +1.0 at synthesis time
(see fluid_mod_get_value()).
That means that this source will behave unipolar only. We need to force the
unipolar flags to ensure the modulator will behave correctly later in
fluid_voice_get_lower_boundary_for_attenuation().
This change removes the warning message if retrieving the soundfont file
modification time fails in the sample cache loader. The warning made sense
while we didn't have mtime support on all platforms, but after switching
to GLibs g_stat, it's no longer needed.
To reduce the number of calls to fluid_get_file_modification_time and also
get rid of a possible race condition, getting the mtime has been moved to
fluid_samplecache_load.
This change also fixes#483 because it removes the bogus warning messages
if a soundfont was loaded from memory by abusing the filename to store a
pointer.
- v variable is renamed min_val for clarity.
- This fix a bug when calculating the possible minimun
value (min_val) of a modulator. min_val should only
be dependant of:
- signs of mapped sources (ie bipolar [-1..+1] or unipolar [0..+1])
- sign of amount.
- absolute value of amount.
If we move UNKN_ID to the bottom of the enum, in the for() cycle inside chunkid() if the value is not found then the "i" variable will be already UNKN_ID.
I tried to check the generated ASM code when WITH_FLOAT macro is defined and when it is undefined. In both cases I noticed that there are some points where the math number are converted from float to double and viceversa. Actually this happens whether the FPU is present or not, perhaps for granting the right precision in digits. I also noticed few points that could be simplified a bit by using integer math, so I also included them.
* Since fluid_voice_get_actual_key() returns an integer value, the value 60 could be subtracted directly as integer, the code generated looks a bit better.
* FLUID_NOISE_FLOOR needs to be cast to fluid_real_t to generate a bit more efficient code.
* DC_OFFSET needs a cast to fluid_real_t to generate a bit more efficient code.
* "last_fres" and "output_rate" are already fluid_real_t, so they do not need type cast.
* "chan_add", "par1_add" and "par2_add" are integer types, so they can be added without FPU. "chan_mul", "par1_mul" and "par2_mul" are already fluid_real_t, so they do not need type cast. Instead, the constant 0.5 needs cast to fluid_real_t to be more efficient.
Libreadline is already used into fluid_istream_readline().
In my opinion, there is no need to have this duplicated code, so I would suggest to move the call to add_history() into fluid_sys.h
Closes#460.
Since 'data' is an integer value clipped between +/-8192 and 'nrpn_scale' is a char value, this calculation could be done with integers and then return the fluid_real_t value.
Addresses #455.
Instead of saving the name of the driver, it would be worth to save to pointer to the selected definition instead.
In this way, the function for deleting the driver does not need to search its name by parsing all the list, but it just needs to call the pointer into the saved definition (less code). This fix can be applied to MIDI drivers too.
I also moved the FLUID_FREE(allnames) inside the "if(allnames != NULL)" block, nothing bad should happen even by keeping that instruction outside, but actually there is no need to call the free if allnames is NULL.
In my opionion, it should be possible to simplify the code by installing the drivers with a for() cycle instead of doing tons of #ifdef...#endif.
The size of the binary code is basically the same as before, but the source lines are much less. I think that it could be done also for MIDI input drivers.
Actually, the function roundi() already returns an "int" type value, so in my opinion there is no need to use a floating point value for saturating the values in the range -32768/+32767. The generated assembly code looks more efficient after that.
- fluid_dsound_audio_run() and fluid_win32_error() are now static functions.
- WAVEFORMATEX is not required by DirectSound during the playback. We do not need it anymore after calling ::SetFormat(), so allocating this structure dynamically inside driver structure is useless.
- Implemented support for float sample type.
- Uses an event object for handling the end of thread, it allows to combine the quit event with the later wait in milliseconds in a single block.
- Calculates the amount of milliseconds to sleep rather than sleeping always for one millisecond.
- Fix an error into a FLUID_LOG() call.
- Fix handle leak of the thread, now it is correctly closed with CloseHandle().
- ExitThread() is a nonsense in that position, since the thread is already exiting.
- Fix error when compiling with WSDK 8.1, by defining NOBITMAP, in case NOGDI macro added somewhere