- Switch to Ubuntu 20.04 Docker image ghcr.io/lmms/linux.gcc:20.04
- Linux packages have migrated from Docker Hub to https://github.com/orgs/lmms/packages
- Built using the Dockerfiles from Update Linux images lmms-ci-docker#15
- Updated the veal submodule to the latest commit on the default ladspa branch
- Fixed an error when catching a polymorphic type with GCC 9. See: LMMS/veal@0ae9287
- Added GCC flag -Wno-format-truncation for ZynAddSubFx build.
- Adds GCC flag -Wno-format-overflow for calf/veal build.
Closes#6993
Oversampling can have many different effects to the audio signal such as latency, phase issues, clipping, smearing, etc, so this should really be an option on a per-plugin basis, not globally across all of LMMS (which, in some places, shouldn't really need to oversample at all but were oversampled anyways).
Add the virtual method `Effect::onEnabledChanged` which can be overridden by effects so that they can react to state changes with regards to being enabled or bypassed. The call of this methods is connected to state changes of the enabled model in the constructor of `Effect`.
Implement the method in `DualFilterEffect` by resetting the history of the two filters. This is done to prevent pops that have been reported in #4612.
The previous implementation of Lb302`s decay used a fixed decay factor that was multiplied with the signal until the minimum threshold of 1/65536 was crossed. This fixed factor resulted in different lengths in time for different sample rates.
This is fixed by computing the decay factor by taking the sample rate into account as well. The new static method `computeDecayFactor` computes the factor that is needed to make a signal decay from 1 to a given attenuation over a given time.
The parameters used in the call to that method in `Lb302Synth::process` have been fine-tuned such that, at a sample rate of 44.1 kHz, they result in a factor very close to the previous hard-coded factor of 0.99897516.
When applying its release stage Kicker did not take the frames before the release into account but instead always applied the release to the full buffer. This potentially lead to a jump in the attenuation values instead of a clean linear decay.
See #7225 for more details.
## Instrument flags as a property of an instrument
The instruments flags (single streamed, MIDI based, not bendable) are properties of an instrument that do not change over time. Therefore the flags are made a property of the instrument which is initialized at construction time.
Adjust the constructors of all instruments which overrode the `flags` method to pass their flags into the `Instrument` constructor.
## Add helper methods for flags
Add helper methods for the flags. This makes the code more concise and readable and clients do not need to know the technical details on how to evaluate a flag.
## Remove the flags methods
Remove the flags methods to make it an implementation detail on how the flags are managed.
Make instruments report their release time in milliseconds so that it becomes independent of the sample rate and sounds the same at any sample rate.
Technically this is done by removing the virtual keyword from `desiredReleaseFrames` so that it cannot be overridden anymore. The method now only serves to compute the number of frames from the given release time in milliseconds.
A new virtual method `desiredReleaseTimeMs` is added which instruments can override. The default returns 0 ms just like the default implementation previously returned 0 frames.
The method `computeReleaseTimeMsByFrameCount` is added for instruments that still use a hard coded release in frames. As of now this is only `SidInstrument`.
Add the helper method `getSampleRate` to `Instrument`.
Adjust several instruments to report their release times in milliseconds. The times are computed by taking the release in frames and assuming a sample rate of 44.1 kHz. In most cases the times are rounded to a "nice" next value, e.g.:
* 64 frames -> 1.5 ms (66 frames)
* 128 frames -> 3.0 ms (132 frames)
* 512 frames -> 12. ms (529 frames)
* 1000 frames -> 23 ms (1014 samples)
In parentheses the number of frames are shown which result from the rounded number of milliseconds when converted back assuming a sample rate of 44.1 kHz. The difference should not be noticeable in existing projects.
Remove the overrides for instruments that return the same value as the base class `Instrument` anyway. These are:
* GigPlayer
* Lb302
* Sf2Player
For `MonstroInstrument` the implementation is adjusted to behave in a very similar way. First the maximum of the envelope release times is computed. These are already available in milliseconds. Then the maximum of that value and 1.5 ms is taken and returned as the result.
## Bump CMT to d8bf8084aa3
Bump the CMT submodule to commit d8bf8084aa3 which contains the underlying fixes for issue #5167.
The CMT delay uses `sprintf` calls to generate the technical names and display names of the delays. These calls are locale dependent. As a consequence for example the feedback delay might have been saved either as "fbdelay_0.1s" (point) or "fbdelay_0,1s" (comma) in a save file.
The CMT fix makes sure that all delays use points in their names and thus that they now always report the same name strings.
## Add upgrade routine for CMT delays
Add an upgrade routine for CMT delays which works in conjunction with the upgraded CMT submodule. Because the delays will now always report their name with points old save files which might contain versions with the comma must be upgraded to a name with a point.
* Render fader levels in code with a gradient
Render the fader level in code using a gradient instead of using pixmaps. The problem with the pixmaps is that they don't "know" how a fader instance is configured with regards to the minimum and maximum value. This means that the display can give quite a wrong impression.
The rendering of levels has been unified in the method `paintLevels`. It can render using dbFS and linear scale. The method `paintLinearLevels` has been removed completely, i.e. there's no more code that renders using pixmaps.
Much of the previous code relied on the size of the background image `fader_background.png`, e.g. the initialization of the size. For now the `Fader` widget is initially resized to the size of that background image as it is present in the default and classic theme (see `Fader::init`). All rendering uses the size of the widget itself to determine where to draw what. This means that the widget is prepared to be resizable.
The method `paintLevels` first renders the background of the level indicators and uses these as clipping paths for all other rendering operations, e.g. for the rendering of the levels themselves. Levels are rendered using a gradient which is defined with the following stops:
* Two stops for the ok levels.
* One stop for warning levels.
* One stop for clipping levels.
Peak indicators do not use the three distinct colors anymore but instead use the color of the gradient at that position of the peak. This makes everything look "smooth".
The code now also renders a marker at unity position, i.e. at position 1.0 in linear levels and 0 dbFS in dbFS scale.
The painting code makes lots of use of the class `PaintHelper`. This class is configured with a minimum and maximum value and can then return linear factors for given values. There are two supported modes:
* Map min to 0 and max to 1
* Map min to 1 and max to 0
It can also compute rectangles that correspond to a given value. These methods can be given rectangles that are supposed to represent the span from min to max. The returned result is then a rectangle that fills the lower part of the source rectangle according to the given value with regards to min and max (`getMeterRect`). Another method returns a rectangle of height 1 which lies inside the given source rectangle at the corresponding level (`getPersistentPeakRect`).
The method `paintLevels` uses a mapping function to map the amplitude values (current peak value, persistent peak, etc.) to the display values. There's one mapper that keeps the original value and it is used to display everything in a linear scale. Another mapper maps everything to dbFS and uses these values as display everything in a dbFS scale. The following values must be mapped for the left and right channel to make this work:
* Min and max display values (min and max peak values)
* The current peak value
* The persistent peak value
* The value for unity, i.e. 1.0 in linear levels and 0 dbFS in dbFS scale.
Remove the method `calculateDisplayPeak` which was used in the old method to render linear levels.
`Fader::setPeak` now uses `std::clamp` instead of doing "manual" comparisons.
The LMMS plugins Compressor, EQ and Delay are still configured to use linear displays. It should be considered to switch them to dbFS/logarithmic displays as well and to remove the code that renders linearly.
* Remove unused pixmaps from `Fader`
Remove the now unused pixmaps for the background and the LEDs from the `Fader` class and remove the files from the default and classic theme directories.
* Rename peak properties and use them to render levels
Rename the peak properties as follows:
* peakGreen -> peakOk
* peakRed -> peakClip
* peakYellow -> peakWarn
The reasoning is that a style might for example use a different color than green to indicate levels that are ok.
Use the properties to initialize the gradient that is used to render the levels.
Initialize the properties to the colors of the current default theme so that it's not mandatory to set them in a style sheet. Up until now they have all been initialized as black.
* Always render the knob in the middle of the fader
Render the knob in the middle of the fader regardless of the width. The previous implementation was dependent on the fader pixmap having a matching width because it always rendered at x=0.
* Set size policy of fader to minimum expanding
Set the size policy of the fader to minimum expanding in both directions. This will make the fader grow in layouts if there is space.
* Default dbFS levels and better peak values
Default to dbFS levels for all faders and set some better minimum and maximum peak values.
* Fix faders of Crossover EQ
Fix the faders of the Crossover EQ which were initialized and rendered much too wide and with a line at unity. The large width also resulted in the knobs being rendered outside of view.
Resize the fader to the minimum size so that it is constructed at a sane default.
Introduce a property that allows to control if the unity line is rendered. The property is available in style sheets and defaults to the unity lines being rendered. Adjust the paint code to evaluate the property.
Initialize the faders of the Crossover EQ such that the unity line is not drawn.
* Remove EqFader constructor with pixmaps
Remove the constructor of `EqFader` that takes the pixmaps to the fader background, leds and knob. The background and leds pixmaps are not used by the base class `Fader` for rendering anymore to make the `Fader` resizable. A pixmap is still used to render the knob but the constructor that takes the knob as an argument does not do anything meaningful with it, i.e. all faders are rendered with the default knob anyway.
Remove the resources for the fader background, leds and knob as they are not used and the knob was the same image as the default knob anyway.
Remove the static pixmaps from the constructor of `EqControlsDialog`. Switch the instantiations of the EQ's faders to use the remaining constructor of `EqFader`. This constructor sets a different fixed size of (23, 116) compared to the removed constructor which set a size of (23, 80). Therefore all faders that used the removed constructor are now set explicitly to a fixed size of (23, 80).
The constructor that's now used also calls a different base constructor than the removed one. The difference between the two base constructors of `Fader` is that one of them sets the member `m_conversionFactor` to 100.0 whereas the other one keeps the default of 1.0. The adjusted faders in `EqControlsDialog` are thus now constructed with the conversion factor set to 100. However, all of them already call `setDisplayConversion` with `false` after construction which results in the conversion factor being reset to 1.0. So the result should be the same as before the changes.
* Remove background and LEDs pixmap from Fader constructor
Remove the parameters for the background and LEDs pixmap from the second `Fader` constructor. Make the knob pixmap parameter in the constructor a const reference. Assign the reference to the knob pixmap of the `Fader` itself. This enables clients to use their own fader knobs as is the case with the Crossover EQ. The EQ now renders using it's own knobs again.
Make the second constructor delegate to the first one. This will additionally set the conversion factor to 100 but this is not a problem with the current code because the only user of the second constructor, the Crossover EQ, already calls `setDisplayConversion` with the parameter set to `false`, hence reinstating a conversion factor of 1.
Remove the resources for the background and LEDs from the Crossover EQ as they are not used anymore. Remove the three QPixmap members from `CrossoverEQControlDialog` as they are not needed. The background and LEDs are not used anyway and the knob is passed in as a constant reference which is copied. Hence we can use a local variable in the constructor of `CrossoverEQControlDialog`.
* Remove the init method from Fader
Remove the `init` method from `Fader` as it is not needed anymore due to the constructor delegation. Tidy up the parameter lists and use of spaces in the constructor.
* Introduce range with solid warn color
Introduce a second point in the gradient for the warn colors so that we get a certain range with the full/solid warn color.
The colors are distributed as follows now. The solid ok range goes from -inf dbFS to -12 dbFS. The warn range goes from -6 dbFS to 0 dbFS. In between the colors are interpolated. Values above 0 dbFS interpolate from the warn color to the clip color.
This is now quite similar to the previous implementation.
# Analysis of the previous pixmap implementation
The pixmap implementation used pixmaps with a height of 116 pixels to map 51 dbFS (-42 dbFS to 9 dbFS) across the whole height. The pixels of the LED pixmap were distributed as follows along the Y-axis:
* Margin: 4
* Red: 18
* Yellow: 14
* Green: 76
* Margin: 4
Due to the margins the actual red, yellow and green areas only represent a range of (1 - (4+4) / 116) * 51 ~ 47,48 dbFS. This range is distributed as follows across the colors:
Red: 7.91 dbFS
Yellow: 6.16 dbFS
Green: 33.41 dbFS
The borders between the colors are located along the following dbFS values:
* Red/yellow: 9 - (4 + 18) / 116 * 51 dbFS ~ -0.67 dbFS
* Yellow/green: 9 - (4 + 18 + 14) / 116 * 51 dbFS ~ -6.83 dbFS
* The green marker is rendered for values above -40.24 dbFS.
* Remove unused method Fader::clips
* Fader: Correctly render arbitrary ranges
Adjust the `Fader` so that it can correctly render arbitrary ranges of min and max peak values, e.g. that it would render a display range of [-12 dbFS, -42 dbFS] correctly.
Until now the gradient was defined to start at the top of the levels rectangle and end at the bottom. As a result the top was always rendered in the "clip" color and the bottom in the "ok" color. However, this is wrong, e.g. if we configure the `Fader` with a max value of -12 dbFS and a min value of -42 dbFS. In that case the whole range of the fader should be rendered with the "ok" color.
The fix is to compute the correct window coordinates of the start and end point of gradient using from the "window" of values that the `Fader` displays and then to map the in-between colors accordingly. See the added comments in the code for more details.
Add the templated helper class `LinearMap` to `lmms_math.h`. The class defines a linear function/map which is initialized using two points. With the `map` function it is then possible to evaluate arbitrary X-coordinates.
* Remove unused methods in PaintHelper
Remove the now unused mapping methods from `PaintHelper`. Their functionality has been replaced with the usage of `LinearMap` in the code.
* Fix some builds
Include `cassert` for some builds that otherwise fail.
* Opaque unity marker with styling option
Make the unity marker opaque by default and enable to style it with the style sheets. None of the two style sheets uses this option though.
* Darker default color for the unity line
* Move code
Move the computation of most mapped values at the top right after the definition of the mapper so that it is readily available in all phases of the painting code.
* Render unity lines in background
Render the unity lines before rendering the levels so that they get overdrawn and do not stick out when they are crossed.
* Don't draw transparent white lines anymore
Don't draw the transparent white lines anymore as they were mostly clipped anyway and only create "smudge".
* Full on clip color at unity
Adjust the gradient so that the full on clip color shows starting at unity. There is only a very short transition from the end of warning to clipping making it look like a solid color "standing" on top of a gradient.
* Fix discrepancy between levels and unity markers
This commit removes the helper class `PaintHelper` and now uses two lambdas to compute the rectangles for the peak indicators and levels. It uses the linear map which maps the peak values (in dbFS or linear) to window coordinates of the widget.
The change fixes a discrepancy in the following implementation for which the full on clip rectangle rendered slightly below the unity marker.
* Fix fader display for Equalizer shelves and peaks
The peak values for the shelves and peaks of the Equalizer plugin are computed in `EqEffect::peakBand`. The previous implementation evaluated the bins of the corresponding frequency spectrum and determined the "loudest" one. The value of this bin was then converted to dbFS and mapped to the interval [0, inf[ where all values less or equal to -60 dbFS were mapped to 0 and a value of 40 dbFS was mapped to 1. So effectively everything was mapped somewhere into [0, 1] yet in a quite "distorted" way because a signal of 40 dbFS resulted in being displayed as unity in the fader.
This commit directly returns the value of the maximum bin, i.e. it does not map first to dbFS and then linearize the result anymore. This should work because the `Fader` class assumes a "linear" input signal and if the value of the bin was previously mapped to dbFS it should have some "linear" character. Please note that this is still somewhat of a "proxy" value because ideally the summed amplitude of all relevant bins in the frequency range would be shown and not just the "loudest" one.
## Other changes
Rename `peakBand` to `linearPeakBand` to make more clear that a linear value is returned.
Handle a potential division by zero by checking the value of `fft->getEnergy()` before using it.
Index into `fft->m_bands` so that no parallel incrementing of the pointer is needed. This also enables the removal of the local variable `b`.
* Improve the rendering of the levels
The levels rendering now more explicitly distinguished between the rendering of the level outline/border and the level meters. The level rectangles are "inset" with regards to the borders so that there is a margin between the level borders and the meter readings. This margin is now also applied to the top and bottom of the levels. Levels are now also rendered as rounded rectangles similar to the level borders.
Only render the levels and peaks if their values are greater than the minimum level.
Make the radius of the rounded rectangles more pronounced by increasing its value from 1 to 2.
Decrease the margins so that the level readings become wider, i.e. so that they are rendered with more pixels.
Add the lambda `computeLevelMarkerRect` so that the rendering of the level markers is more decoupled from the rendering of the peak markers.
* Reduce code repetition
Reduce code repetition in `EqEffect::setBandPeaks` by introducing a lambda. Adjust code formatting.
* Code review changes
Code review changes in `Fader.cpp`. Mostly whitespace adjustments.
Split up the calculation of the meter width to make it more understandable. This also reduces the number of parentheses.
* Use MEMBER instead of READ/WRITE
Use `MEMBER` instead of `READ`/`WRITE` for some properties that are not called explicitly from outside of the class.
* Use default member initializers for Fader
Use default member initializers for the members in `Fader` that have previously been initialized in the constructor list.
* Make code clearer
Make code clearer in `Fader::FadermouseDoubleClickEvent`. Only divide if the dialog was accepted with OK.
Adjust and rename the function `pointSize` so that it sets the font size in pixels. Rename `pointSize` to `adjustedToPixelSize` because that's what it does now. It returns a font adjusted to a given pixel size. Rename `fontPointer` to `font` because it's not a pointer but a copy. Rename `fontSize` to simply `size`.
This works if the intended model is that users use global fractional scaling. In that case pixel sized fonts are also scaled so that they should stay legible for different screen sizes and pixel densities.
## Adjust plugins with regards to adjustedToPixelSize
Adjust the plugins with regards to the use of `adjustedToPixelSize`.
Remove the explicit setting of the font size of combo boxes in the following places to make the combo boxes consistent:
* `AudioFileProcessorView.cpp`
* `DualFilterControlDialog.cpp`
* `Monstro.cpp` (does not even seem to use text)
* `Mallets.cpp`
Remove calls to `adjustedToPixelSize` in the following places because they can deal with different font sizes:
* `LadspaBrowser.cpp`
Set an explicit point sized font size for the "Show GUI" button in `ZynAddSubFx.cpp`
Increase the font size of the buttons in the Vestige plugin and reduce code repetition by introducing a single variable for the font size.
I was not able to find out where the font in `VstEffectControlDialog.cpp` is shown. So it is left as is for now.
## Adjust the font sizes in the area of GUI editors and instruments.
Increase the font size to 10 pixels in the following places:
* Effect view: "Controls" button and the display of the effect name at the bottom
* Automation editor: Min and max value display to the left of the editor
* InstrumentFunctionViews: Labels "Chord:", "Direction:" and "Mode:"
* InstrumentMidiIOView: Message display "Specify the velocity normalization base for MIDI-based instruments at 100% note velocity."
* InstrumentSoundShapingView: Message display "Envelopes, LFOs and filters are not supported by the current instrument."
* InstrumentTuningView: Message display "Enables the use of global transposition"
Increase the font size to 12 pixels in the mixer channel view, i.e. the display of the channel name.
Render messages in system font size in the following areas because there should be enough space for almost all sizes:
* Automation editor: Message display "Please open an automation clip by double-clicking on it!"
* Piano roll: Message display "Please open a clip by double-clicking on it!"
Use the application font for the line edit that can be used to change the instrument name.
Remove overrides which explicitly set the font size for LED check boxes in:
* EnvelopeAndLfoView: Labels "FREQ x 100" and "MODULATE ENV AMOUNT"
Remove overrides which explicitly set the font size for combo boxes in:
* InstrumentSoundShapingView: Filter combo box
## Adjust font sizes in widgets
Adjust the font sizes in the area of the custom GUI widgets.
Increase and unify the pixel font size to 10 pixels in the following classes:
* `ComboBox`
* `GroupBox`
* `Knob`
* `LcdFloatSpinBox`
* `LcdWidget`
* `LedCheckBox`
* `Oscilloscope`: Display of "Click to enable"
* `TabWidget`
Shorten the text in `EnvelopeAndLfoView` from "MODULATE ENV AMOUNT" to "MOD ENV AMOUNT" to make it fit with the new font size of `LedCheckBox`.
Remove the setting of the font size in pixels from `MeterDialog` because it's displayed in a layout and can accommodate all font sizes. Note: the dialog can be triggered from a LADSPA plugin with tempo sync, e.g. "Allpass delay line". Right click on the time parameter and select "Tempo Sync > Custom..." from the context menu.
Remove the setting of the font size in `TabBar` as none of the added `TabButton` instances displays text in the first place.
Remove the setting of the font size in `TabWidget::addTab` because the font size is already set in the constructor. It would be an unexpected size effect of setting a tab anyway. Remove a duplicate call to setting the font size in `TabWidget::paintEvent`.
Remove unnecessary includes of `gui_templates.h` wherever this is possible now.
## Direct use of setPixelSize
Directly use `setPixelSize` when drawing the "Note Velocity" and "Note Panning" strings as they will likely never be drawn using point sizes.
* clang-tidy: Apply cppcoreguidelines-init-variables everywhere (treating NaNs as zeros)
* Initialize msec and tick outside switch
* Update plugins/Vestige/Vestige.cpp
Co-authored-by: Kevin Zander <veratil@gmail.com>
* Update plugins/Vestige/Vestige.cpp
Co-authored-by: Kevin Zander <veratil@gmail.com>
* Update plugins/Vestige/Vestige.cpp
Co-authored-by: Kevin Zander <veratil@gmail.com>
* Update plugins/VstEffect/VstEffectControls.cpp
Co-authored-by: Kevin Zander <veratil@gmail.com>
* Update src/core/DrumSynth.cpp
Co-authored-by: Kevin Zander <veratil@gmail.com>
* Update plugins/VstEffect/VstEffectControls.cpp
Co-authored-by: Kevin Zander <veratil@gmail.com>
* Update plugins/VstEffect/VstEffectControls.cpp
Co-authored-by: Kevin Zander <veratil@gmail.com>
* Update src/core/DrumSynth.cpp
Co-authored-by: Kevin Zander <veratil@gmail.com>
* Update src/core/DrumSynth.cpp
Co-authored-by: Kevin Zander <veratil@gmail.com>
* Update src/core/DrumSynth.cpp
Co-authored-by: Kevin Zander <veratil@gmail.com>
* Update src/core/DrumSynth.cpp
Co-authored-by: Kevin Zander <veratil@gmail.com>
* Update src/core/DrumSynth.cpp
Co-authored-by: Kevin Zander <veratil@gmail.com>
* Update src/core/DrumSynth.cpp
Co-authored-by: Kevin Zander <veratil@gmail.com>
* Use initialization with =
* Use tabs
* Use static_cast
* Update DrumSynth.cpp
Co-authored-by: Kevin Zander <veratil@gmail.com>
* Update DrumSynth.cpp
Co-authored-by: Kevin Zander <veratil@gmail.com>
* Update DrumSynth.cpp
Co-authored-by: Kevin Zander <veratil@gmail.com>
* Update src/core/DrumSynth.cpp
Co-authored-by: Kevin Zander <veratil@gmail.com>
* Do not use tabs for alignment in src/core/DrumSynth.cpp
Co-authored-by: Dalton Messmer <messmer.dalton@gmail.com>
* Move x variable inside loop
* Use ternary operator for b variable
* Revert "Use tabs"
This reverts commit 07afd8a83f58b539c3673310b2aad4b63c9198a0.
* Remove unnecessary variables in XpressiveView
* Simplify initialization in Plugin
* Combine declaration and initialization in EqCurve
* Combine declaration and initialization in Song
* Combine declaration and initialization in AudioAlsa
* Combine declaration and initialization in EqCurve (again)
* Missed some
* Undo changes made to non-LMMS files
* Undo indentation changes in SidInstrument.cpp
* Combine declaration with assignment in IoHelper
* Combine declaration with assignment using auto in Carla
* Combine declaration with assignment
* Combine declaration with assignment in BasicFilters
* Simplify assignments in AudioFileProcessorWaveView::zoom
* Simplify out sample variable in BitInvader
* Remove sampleLength variable in DelayEffect
* Move gain variable in DynamicsProcessor
* Combine peak variable declaration with assignment in EqSpectrumView
* Move left/right lfo variables in for loop in FlangerEffect
* Use ternary operator for group variable in LadspaControlDialog
* Combine declaration with assignment in Lb302
* Combine declaration with assignment in MidiExport
* Combine declaration with assignment in MidiFile
* Combine declaration with assignment in MidiImport
* Use ternary operator for vel_adjusted variable in OpulenZ
* Move tmpL and dcblkL variables in for loop in ReverbSC
* Combine declaration with initialization in SlicerT
* Combine declaration with assignment in SaSpectrumView
* Combine declaration with assignment in SaWaterfallView
* Combine declaration with assignment in StereoEnhancerEffect
* Combine declaration with assignment in VibratingString
* Combine declaration with assignment in VstEffectControls
* Combine declaration with assignment in Xpressive
* Combine declaration with assignment in AutomatableModel
* Combine declaration with assignment in AutomationClip
* Move sample variable in for loop in BandLimitedWave
* Combine declaration with assignment in DataFile
* Combine declaration with assignment in DrumSynth
* Combine declaration with assignment in Effect
* Remove redundant assignment to nphsLeft in InstrumentPlayHandle
* Combine declaration with assignment in LadspaManager
* Combine declaration with assignment in LinkedModelGroups
* Combine declaration with assignment in MemoryHelper
* Combine declaration with assignment in AudioAlsa
* Combine declaration with assignment in AudioFileOgg
* Combine declaration with assignment in AudioPortAudio
* Combine declaration with assignment in AudioSoundIo
* Combine declaration with assignment in Lv2Evbuf
* Combine declaration with assignment in Lv2Proc
* Combine declaration with assignment in main
* Combine declaration with assignment in MidiAlsaRaw
* Combine declaration with assignment in MidiAlsaSeq
* Combine declaration with assignment in MidiController
* Combine declaration with assignment in MidiJack
* Combine declaration with assignment in MidiSndio
* Combine declaration with assignment in ControlLayout
* Combine declaration with assignment in MainWindow
* Combine declaration with assignment in ProjectNotes
* Use ternary operator for nextValue variable in AutomationClipView
* Combine declaration with assignment in AutomationEditor
* Move length variable in for-loop in PianoRoll
* Combine declaration with assignment in ControllerConnectionDialog
* Combine declaration with assignment in Graph
* Combine declaration with assignment in LcdFloatSpinBox
* Combine declaration with assignment in TimeDisplayWidget
* Remove currentNote variable in InstrumentTrack
* Combine declaration with assignment in DrumSynth (again)
* Use ternary operator for factor variable in BitInvader
* Use ternary operator for highestBandwich variable in EqCurve
Bandwich?
* Move sum variable into for loop in Graph
* Fix format in MidiSndio
* Fixup a few more
* Cleanup error variables
* Use ternary operators and combine declaration with initialization
* Combine declaration with initialization
* Update plugins/LadspaEffect/LadspaControlDialog.cpp
Co-authored-by: Kevin Zander <veratil@gmail.com>
* Update plugins/OpulenZ/OpulenZ.cpp
Co-authored-by: Kevin Zander <veratil@gmail.com>
* Update plugins/SpectrumAnalyzer/SaProcessor.cpp
Co-authored-by: Kevin Zander <veratil@gmail.com>
* Update src/core/midi/MidiAlsaRaw.cpp
Co-authored-by: Kevin Zander <veratil@gmail.com>
* Update src/gui/MainWindow.cpp
Co-authored-by: Kevin Zander <veratil@gmail.com>
* Update src/gui/clips/AutomationClipView.cpp
Co-authored-by: Kevin Zander <veratil@gmail.com>
* Update src/gui/editors/AutomationEditor.cpp
Co-authored-by: Kevin Zander <veratil@gmail.com>
* Update src/gui/widgets/Fader.cpp
Co-authored-by: Kevin Zander <veratil@gmail.com>
* Move static_cast conversion into separate variable
* Use real index when interpolating
* Remove empty line
* Make helpBtn a private member
* Move controller type into separate variable
* Fix format of DrumSynth::waveform function
* Use tabs and static_cast
* Remove redundant if branch
* Refactor using static_cast/reinterpret_cast
* Add std namespace prefix
* Store repeated conditional into boolean variable
* Cast to int before assigning to m_currentLength
* Rename note_frames to noteFrames
* Update src/core/Controller.cpp
Co-authored-by: Kevin Zander <veratil@gmail.com>
* Update src/core/DrumSynth.cpp
Co-authored-by: Kevin Zander <veratil@gmail.com>
* Update src/gui/widgets/Graph.cpp
Co-authored-by: Kevin Zander <veratil@gmail.com>
* Revert changes that initialized variables redudantly
For situations where the initialization is
more complex or passed into a function
by a pointer, we dont need to do
initialization ourselves since it is
already done for us, just in a different way.
* Remove redundant err variable
* Remove explicit check of err variable
* Clean up changes and address review
* Do not initialize to 0/nullptr when not needed
* Wrap condition in parentheses for readability
---------
Co-authored-by: Kevin Zander <veratil@gmail.com>
Co-authored-by: Dalton Messmer <messmer.dalton@gmail.com>
* remove the gui_templates header where functions not used
* refactor and replace template with function argument
* refactor: merge pointSizeF function with pointSize
* removed template per michael's review
* use std::max for more readability
* remove the QDesktopWidget header
* cleanup arguments and remove parentheses from return
* replace QRegExp with QRegularExpression (find n replace)
* follow up to fix errors
* removed rpmalloc
* Fix compilation for qt5, to be fixed when qt6 fully supported.
Co-authored-by: Kevin Zander <veratil@gmail.com>
* Added QtGlobal header for version finding fix
* Use the other syntax to try fix compilation.
* Check for 5.12 instead.
* Fix the header
* Attempt at fixing it further.
* Use version checks properly in header file
* Use QT_VERSION_CHECK macro in sources
* Apply suggestions from messmerd's review
Co-authored-by: Dalton Messmer <messmer.dalton@gmail.com>
---------
Co-authored-by: Kevin Zander <veratil@gmail.com>
Co-authored-by: Dalton Messmer <messmer.dalton@gmail.com>
Fix several NaNs in the context of the basic filters and the Equalizer.
The coefficients of the `BiQuad` were not initialized which seems to have led to NaNs down the line.
Fix a division by zero in `EqEffect::peakBand` and `EqSpectrumView::paintEvent` if the energy is zero.
The condition `m_peakSum <= 0` was removed from `EqSpectrumView::paintEvent` because the value is initialized to 0 down the line and later only potentially positive values are added.
Removes `MemoryManager` and the use of rpmalloc in favor of the `new` and `delete` operators found in C++.
---------
Co-authored-by: Veratil <veratil@gmail.com>
* Fix crash in Audio File Processor
Fix a crash in the Audio File Processor that occurs when an Audio File Processor with a reversed sample is loaded from a save file and then the plugin window is opened.
The problem was caused by a call to `AudioFileProcessorWaveView::slideSampleByFrames` during the execution of constructor of `AudioFileProcessorWaveView`. In that situation the three `knob` members were all `nullptr` because for some reason there was an explicit setter for them which was only called after construction. This is fixed by passing and setting the knobs in the constructor.
Another question is if it's not a problem in the first place that the knobs are given to the `AudioFileProcessorWaveView` instead of their underlying models.
On plugin instantiation failure, `Lv2Proc::m_valid` was being set to false. However, `Lv2Proc::run` did not evaluate `m_valid` and still called `lilv_instance_run`, which caused undefined behavior, including crashes.
This bug fixes this by not even create such zombie classes, and instead `throw`s right away. The throws are caught in `lmms_plugin_main`, as suggested in the PR discussion and as the VST3 approach.
* Add private setters for "from" and "to"
Add private setters for the "from" and "to" values in `AudioFileProcessorWaveView`. When being used the setters will ensure that the bounds are respected.
Also add a `range` method because this computation was done repeatedly throughout the code.
Fixes#7068 but masks some of the original problems with the code that computes out-of-bounds values for "from" and "to" like the `slide` method. Problematic code can still be found by temporarily adding the following assertions to the setters:
* `assert (to <= m_sample->sampleSize());` in `setTo`
* `assert (from >= 0);` in `setFrom`
* Remove superfluous calls to qMax and qMin
## Extract views
Extract the classes `AudioFileProcessorWaveView` and `AudioFileProcessorView` into their own files.
Reformat the new classes by removing unnecessary whitespace and underscores. Add spaces to if-statements.
Cleanup the includes.
## Remove friend relationship
Remove the friend relationship between `AudioFileProcessor` and `AudioFileProcessorView`.
Introduce getters for entities that the view is interested in.
* Handle divisions by 0 in Lb302
Handle potential division by 0 which in turn lead to floating point exceptions in Lb302. The division can occur in the `process` method if it is called with the member `vco_inc` still initialized to 0. This seems to happen then the Lb302 processes with no notes actually being played.
The offending call is `BandLimitedWave::pdToLen(vco_inc)` which is now prevented when the increment is 0. In the latter case a sample of 0 is produced. This works because in all other cases the Lb302 instance should process a note which in turn sets the increments to something different from 0.
* Fix FPEs in Monstro
Fix some floating point exceptions in `MonstroSynth::renderOutput` that occurred due to calling `BandLimitedWave::pdToLen` with a value of 0. This happened when one of the phase deltas was set to 0, i.e. `pd_l` or `pd_r`. These cases are now checked and produce silence in the corresponding components if the phase delta is set to 0.
* Fix uninitialized variables
Initialize the local variables `len_l` and `len_r` to 0. This fixes compiler warnings a la "error: 'len_r' may be used uninitialized in this function" which are treated as errors on the build server.
* Adjust whitespace of touched code
Fix the peak update of the LMMS equalizer which accidentally used the same sample twice.
Simplify the `gain` method by removing repeated deferences which made the code hard to read.
Use `std::max` to update the peak values to the maximum of the buffer.
Remove the code which computes a minimum height for the LADSPA dialogs. It was intended to make sure that no scrollbar is shown in most cases. However, doing so came at the cost that the computed height was the minimum height as well. Therefore the dialogs took a lot of space on low-res displays and could not be made smaller.
After the removal the behavior is still sane. Small dialogs are shown in full and dialogs which are larger, e.g. "Calf Equalizer 12 Band LADSPA", seem to be sized around half the height of the workspace and show scrollbars.
* Add refactored SampleBuffer
* Add Sample
* Add SampleLoader
* Integrate changes into AudioSampleRecorder
* Integrate changes into Oscillator
* Integrate changes into SampleClip/SamplePlayHandle
* Integrate changes into Graph
* Remove SampleBuffer include from SampleClipView
* Integrate changes into Patman
* Reduce indirection to sample buffer from Sample
* Integrate changes into AudioFileProcessor
* Remove old SampleBuffer
* Include memory header in TripleOscillator
* Include memory header in Oscillator
* Use atomic_load within SampleClip::sample
* Include memory header in EnvelopeAndLfoParameters
* Use std::atomic_load for most calls to Oscillator::userWaveSample
* Revert accidental change on SamplePlayHandle L.111
* Check if audio file is empty before loading
* Add asserts to Sample
* Add cassert include within Sample
* Adjust assert expressions in Sample
* Remove use of shared ownership for Sample
Sample does not need to be wrapped around a std::shared_ptr.
This was to work with the audio thread, but the audio thread
can instead have their own Sample separate from the UI's Sample,
so changes to the UI's Sample would not leave the audio worker thread
using freed data if it had pointed to it.
* Use ArrayVector in Sample
* Enforce std::atomic_load for users of std::shared_ptr<const SampleBuffer>
* Use requestChangesGuard in ClipView::remove
Fixes data race when deleting SampleClip
* Revert only formatting changes
* Update ClipView::remove comment
* Revert "Remove use of shared ownership for Sample"
This reverts commit 1d452331d1.
In some cases, you can infact do away with shared ownership
on Sample if there are no writes being made to either of them,
but to make sure changes are reflected to the object in cases
where writes do happen, they should work with the same one.
* Fix heap-use-after-free in Track::loadSettings
* Remove m_buffer asserts
* Refactor play functionality (again)
The responsibility of resampling the buffer
and moving the frame index is now in Sample::play, allowing the removal
of both playSampleRangeLoop and playSampleRangePingPong.
* Change copyright
* Cast processingSampleRate to float
Fixes division by zero error
* Update include/SampleLoader.h
Co-authored-by: Dalton Messmer <33463986+messmerd@users.noreply.github.com>
* Update include/SampleLoader.h
Co-authored-by: Dalton Messmer <33463986+messmerd@users.noreply.github.com>
* Format SampleLoader.h
* Remove SampleBuffer.h include in SampleRecordHandle.h
* Update src/core/Oscillator.cpp
Co-authored-by: Dalton Messmer <33463986+messmerd@users.noreply.github.com>
* Use typeInfo<float> for float equality comparison
Co-authored-by: Dalton Messmer <33463986+messmerd@users.noreply.github.com>
* Use std::min in Sample::visualize
Co-authored-by: Dalton Messmer <33463986+messmerd@users.noreply.github.com>
* Move in result to m_data
* Use if block in playSampleRange
* Pass in unique_ptr to SampleClip::setSampleBuffer
* Return const QString& from SampleBuffer::audioFile
* Do not pass in unique_ptr by r-value reference
* Use isEmpty() within SampleClipView::updateSample
* Remove use of atomic_store and atomic_load
* Remove ArrayVector comment
* Use array specialization for unique_ptr when managing DrumSynth data
Also made it so that we don't create result
before checking if we failed to decode the file,
potentially saving us an allocation.
* Don't manually delete Clip if it has a Track
* Clean up generateAntiAliasUserWaveTable function
Also, make it so that we actually call this function
when necessary in TripleOscillator.
* Set user wave, even when value is empty
If the value or file is empty, I think showing a
error popup here is ideal.
* Remove whitespace in EnvelopeAndLfoParameters.cpp L#121
* Fix error in c5f7ccba49
We still have to delete the Clip's, or else we would just be eating
up memory. But we should first make sure that the Track's no longer
see this Clip in their m_clips vector. This has to happen
as it's own operation because we have to wait for the audio thread(s)
first. This would ensure that Track's do not create
PlayHandle's that would refer to a Clip that is currently
being destroyed. After that, then we call deleteLater on the Clip.
* Convert std::shared_ptr<Sample> to Sample
This conversion does not apply to Patman as there seems to be issues
with it causing heap-use-after-free issues, such as with
PatmanInstrument::unloadCurrentPatch
* Fix segfault when closing LMMS
Song should be deleted before AudioEngine.
* Construct buffer through SampleLoader in FileBrowser's previewFileItem function
+ Remove const qualification in SamplePlayHandle(const QString&)
constructor for m_sample
* Move guard out of removeClip and deleteClips
+ Revert commit 1769ed517d since
this would fix it anyway
(we don't try to lock the engine to
delete the global automation track when closing LMMS now)
* Simplify the switch in play function for loopMode
* Add SampleDecoder
* Add LMMS_HAVE_OGGVORBIS comment
* Fix unused variable error
* Include unordered_map
* Simplify SampleDecoder
Instead of using the extension (which could be wrong) for the file,
we simply loop through all the decoders available. First sndfile because
it covers a lot of formats, then the ogg decoder for the few cases where sndfile
would not work for certain audio codecs, and then the DrumSynth decoder.
* Attempt to fix Mac builds
* Attempt to fix Mac builds take 2
* Add vector include to SampleDecoder
* Add TODO comment about shared ownership with clips
Calls to ClipView::remove may occur at any point, which can cause
a problem when the Track is using the clip about to be removed.
A suitable solution would be to use shared ownership between the Track
and ClipView for the clip. Track's can then simply remove the shared
pointer in their m_clips vector, and ClipView can call reset on the
shared pointer on calls to ClipView::remove.
* Adjust TODO comment
Disregard the shared ownership idea. Since we would be modifying
the collection of Clip's in Track when removing the Clip, the Track
could be iterating said collection while this happens,
causing a bug. In this case, we do actually
want a synchronization mechanism.
However, I didn't mention another separate issue in the TODO comment
that should've been addressed: ~Clip should not be responsible for
actually removing the itself from it's Track. With calls to removeClip,
one would expect that to already occur.
* Remove Sample::playbackSize
Inside SampleClip::sampleLength, we should be using Sample::sampleSize
instead.
* Fix issues involving length of Sample's
SampleClip::sampleLength should be passing the Sample's sample rate to
Engine::framesPerTick.
I also changed sampleDuration to return a std::chrono::milliseconds
instead of an int so that the callers know what time interval
is being used.
* Simplify if condition in src/gui/FileBrowser.cpp
Co-authored-by: Dalton Messmer <33463986+messmerd@users.noreply.github.com>
* Simplify if condition in src/core/SampleBuffer.cpp
Co-authored-by: Dalton Messmer <33463986+messmerd@users.noreply.github.com>
* Update style in include/Oscillator.h
Co-authored-by: Dalton Messmer <33463986+messmerd@users.noreply.github.com>
* Format src/core/SampleDecoder.cpp
Co-authored-by: Dalton Messmer <33463986+messmerd@users.noreply.github.com>
* Set the sample rate to be that of the AudioEngine by default
I also removed some checks involving the state of the SampleBuffer.
These functions should expect a valid SampleBuffer each time.
This helps to simplify things since we don't have to validate it
in each function.
* Set single-argument constructors in Sample and SampleBuffer to be explicit
* Do not make a copy when reading result from the decoder
* Add constructor to pass in vector of sampleFrame's directly
* Do a pass by value and move in SampleBuffer.cpp
Co-authored-by: Dalton Messmer <33463986+messmerd@users.noreply.github.com>
* Pass vector by value in SampleBuffer.h
Co-authored-by: Dalton Messmer <33463986+messmerd@users.noreply.github.com>
* Make Sample(std::shared_ptr) constructor explicit
* Properly draw sample waveform when reversed
* Collect sample not found errors when loading project
Also return empty buffers when trying to load
either an empty file or empty Base64 string
* Use std::make_unique<SampleBuffer> in SampleLoader
* Fix loop modes
* Limit sample duration to [start, end] and not the entire buffer
* Use structured binding to access buffer
* Check if GUI exists before displaying error
* Make Base64 constructor pass in the string instead
* Remove use of QByteArray::fromBase64Encoding
* Inline simple functions in SampleBuffer
* Dynamically include supported audio file types
* Remove redundant inline specifier
Co-authored-by: Dalton Messmer <33463986+messmerd@users.noreply.github.com>
* Translate file types
* Cache calls to SampleDecoder::supportedAudioTypes
* Fix translations in SampleLoader (again)
Also ensure that all the file types are listed first.
Also simplified the generation of the list a bit.
* Store static local variable for supported audio types instead of in the header
Co-authored-by: Dalton Messmer <33463986+messmerd@users.noreply.github.com>
* Clamp frame index depending on loop mode
* Inline member functions of PlaybackState
* Do not collect errors in SampleLoader when loading projects
Also fix conflicts with surrounding codebase
* Default construct shared pointers to SampleBuffer
* Simplify and optimize Sample::visulaize()
* Remove redundant gui:: prefix
* Rearrange Sample::visualize after optimizations by DanielKauss
* Apply amplification when visualizing sample waveforms
* Set default min and max values to 1 and -1
* Treat waveform as mono signal when visualizing
* Ensure visualization works when framesPerPixel < 1
* Simplify Sample::visualize a bit more
* Fix CPU lag in Sample by using atomics (with relaxed ordering)
Changing any of the frame markers originally took a writer
lock on a mutex.
The problem is that Sample::play took a reader lock first before
executing. Because Sample::play has to wait on the writer, this
created a lot of lag and raised the CPU meter. The solution
would to be to use atomics instead.
* Fix errors from merge
* Fix broken LFO controller functionality
The shared_ptr should have been taken by reference.
* Remove TODO
* Update EnvelopeAndLfoView.cpp
Co-authored-by: Dalton Messmer <messmer.dalton@gmail.com>
* Update src/gui/clips/SampleClipView.cpp
Co-authored-by: Dalton Messmer <messmer.dalton@gmail.com>
* Update plugins/SlicerT/SlicerT.cpp
Co-authored-by: Dalton Messmer <messmer.dalton@gmail.com>
* Update plugins/SlicerT/SlicerT.cpp
Co-authored-by: Dalton Messmer <messmer.dalton@gmail.com>
* Store shortest relative path in SampleBuffer
* Tie up a few loose ends
* Use sample_rate_t when storing sample rate in SampleBuffer
* Add missing named requirement functions and aliases
* Use sampledata attribute when loading from Base64 in AFP
* Remove initializer for m_userWave in the constructor
* Do not use trailing return syntax when return is void
* Move decoder functionality into unnamed namespace
* Remove redundant gui:: prefix
* Use PathUtil::toAbsolute to simplify code in SampleLoader::openAudioFile
* Fix translations in SampleLoader::openAudioFile
Co-authored-by: DomClark <mrdomclark@gmail.com>
* Fix formatting for ternary operator
* Remove redundant inlines
* Resolve UB when decoding from Base64 data in SampleBuffer
* Fix up SampleClip constructors
* Add AudioResampler, a wrapper class around libsamplerate
The wrapper has only been applied to Sample::PlaybackState for now.
AudioResampler should be used by other classes in the future that do
resampling with libsamplerate.
* Move buffer when moving and simplify assignment functions in Sample
* Move Sample::visualize out of Sample and into the GUI namespace
* Initialize supportedAudioTypes in static lambda
* Return shared pointer from SampleLoader
* Create and use static empty SampleBuffer by default
* Fix header guard in SampleWaveform.h
* Remove use of src_clone
CI seems to have an old version of libsamplerate and does not have this method.
* Include memory header in SampleBuffer.h
* Remove mutex and shared_mutex includes in Sample.h
* Attempt to fix string operand error within AudioResampler
* Include string header in AudioResampler.cpp
* Add LMMS_EXPORT for SampleWaveform class declaration
* Add LMMS_EXPORT for AudioResampler class declaration
* Enforce returning std::shared_ptr<const SampleBuffer>
* Restrict the size of the memcpy to the destination size, not the source size
* Do not make resample const
AudioResampler::resample, while seemingly not changing the data of the resampler, still alters its internal state and therefore should not be const.
This is because libsamplerate manages state when
resampling.
* Initialize data.end_of_input
* Add trailing new lines
* Simplify AudioResampler interface
* Fix header guard prefix to LMMS_GUI instead of LMMS
* Remove Sample::resampleSampleRange
---------
Co-authored-by: Dalton Messmer <33463986+messmerd@users.noreply.github.com>
Co-authored-by: Daniel Kauss <daniel.kauss.serna@gmail.com>
Co-authored-by: Dalton Messmer <messmer.dalton@gmail.com>
Co-authored-by: DomClark <mrdomclark@gmail.com>