* 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>
Revert some of the changes made in commit 88e0e94dcd. The underlying idea was that the `InstrumentTrackView` should be responsible for assigning the icon that's shown by its `TrackLabelButton`. However, this does not work because in some cases the `InstrumentTrack` that's passed into `InstrumentTrackView::determinePixmap` does not have an `Instrument` assigned. This in turn seems to be caused due to initalizations that are running in parallel in different threads.
Here are the steps to reproduce the threading problem (line numbers refer to commit 360254f):
1. Set a break point in line 1054 of `InstrumentTrack`, i.e. the line in `InstrumentTrack::loadInstrument` where `m_instrument` is being assigned to.
2. Set a break point in `InstrumentTrackView::determinePixmap`, e.g. inside of the first if statement.
3. Drop an instance of "Sf2 Player" onto the Song Editor.
4. The first break point in `InstrumentTrack` is hit in a thread called "lmms::Instrumen" (shown like that in my debugger). Try to step over it.
5. The second break point in `InstrumentTrackView` now gets hit before the code is stepped over. This time we are in the thread called "lmms". I guess this is the GUI main thread.
6. Continue execution.
If you now switch to the application then the icon is shown. I guess the debugger is halted long enough in the main thread so that the InstrumentTrack gets an instrument assigned in another thread.
If you delete/disable the break point in `InstrumentTrack::determinePixmap` and follow the coarse steps above then the icon is not shown because the track has no instrument.
The current fix still delegates to the `InstrumentTrackView` to determine the pixmap in hopes that one day there will be a better solution where the parent component can be fully responsible for its child component.
Fixes#7116.
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.
Reenable zooming in the song editor by
* only resizing the track if the alt modifier is pressed and
* only accepting the wheel even if we in fact resize the track.
By doing so all other wheel events bubble up so that zooming and scrolling of the song editor can be handled by parent components.
The code that handles the retrieval of the delta value had to be adjusted as well. The reason is that pressing the alt key messes with the way that deltas are reported in the wheel event. The wheel event is interpreted as a horizontal scroll when alt is pressed.
* Fix invalidated iterator when removing notes in Piano Roll
* fixup - typo
* Add MidiClip::removeNote(iterator) function
* Use iterator version of remoteNote
* Fix parameter name
* Change variable name again
* Simplify TrackLabelButton
Remove the dependency to `Instrument` and `InstrumentTrack` from `TrackLabelButton`. The icon of an `InstrumentTrackView` is now determined in the class `InstrumentTrackView` itself using the new static method `determinePixmap`. This enables the removal of the overridden `paintEvent` method from `TrackLabelButton`.
It was also attempted to keep a non-static member function version and to use the `InstrumentTrackView`'s model with a cast. However, this did not work because 'setModel' is executed as the very last step in the constructor, i.e. the model is not already set when `determinePixmap` is called. Pulling it to the top is too risky right now.
* Add helper method isInCompactMode
Add the helper method `isInCompactMode` which knows how to use the `ConfigManager` to determine if the option for compact track buttons is enabled. This removes duplicate code with intricate knowledge of the keys under which compact mode is stored.
* Set song as modified when track name changes
Extend `Track::setName` to set the song as modified whenever the track name changes. This moves the update into a core class and enables the removal of the dependencies to `Engine` and `Song` from the GUI class `TrackLabelButton`.
Also add a check if the name is really changed and only perform the actions if that's the case.
To make this work the implementation of `setName` had to be moved from the header into the implementation file.
* Keep instrument and sample content at top on resize
Keep the content of the instrument and sample track at the top of the widget if the widget is resized. This is also fixes a bug where the `TrackLabelButton` does not react anymore when the size is increased.
Technically the layout with the actual widgets is put into another vertical layout with a spacer that consumes all remaining space at the bottom.
* Vertical track resizing via mouse wheel
Enable to vertically resize tracks using the mouse wheel. Scrolling the mouse wheel over the track view with the control key pressed will increase/decrease the height by one pixel per wheel event. Pressing the shift key will increase/decrease in steps of five pixels.
Extract code that can be shared between the existing and the new way to resize the track into the private helper method `resizeToHeight`.
* Render beat pattern step buttons at the top
Render the step buttons of beat patterns at the top instead of at the bottom so that they stay aligned with the other elements to the left of them (buttons, knobs, etc).
Set the y offset to 4 so that the step buttons are vertically aligned with the other elements. The previous calculation lead to a minimum offset of 6 which always made the step buttons look misaligned.
Introduce the new static variable `BeatStepButtonOffset` which ensures that the rendering and the evaluation of mouse clicks do not go out of sync.
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.
This revisits two main aspects of playback from `Sample`: copying frames into a temporary playback buffer before resampling, and advancing the state's frame index. Both operations were improperly done, causing distorted audio to be heard when resampling from within the `Sample::play` function.
To fix this, playback into the temporary playback buffer is now done using the `playRaw` function, which copies the frame one by one in a loop, moving through the buffer correctly as determined by the loop mode. In addition, advancement of the playback index is done using the `advance` function, which advances the index by the given amount and handles an out of bounds index for the loop modes as necessary using the modulo operator.
Hide the LED button for "Custom Base Velocity" as it did not have any other effect besides disabling the spinbox in the GUI. It did not affect any model which could be evaluated elsewhere.
## Technical details
Add functionality to show/hide the LED button to `GroupBox`. There's also a corresponding getter called `ledButtonShown`. The latter is evaluated in the following situations:
* Mouse clicks: if the LED button is hidden then the model is not toggled.
* Paining: The X position of the caption changes depending on whether the LED button is shown or not.
At a certain point the class `GroupBox` should be replaced by something that's implemented with layouts and which is used wherever it's possible.
* 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.
Fixes most of the problem that the MIDI port information is not cloned when a track is cloned.
The bug was caused because cloning is implemented via serialization and deserialization of the Track. The previous code only serialized the MIDI port if `Engine::getSong()->isSavingProject()` is true. However, when we are cloning the statement will be `false` because we are not saving the song. Therefore the MIDI port's state was not saved and the clone was initialized with the default values.
The fix is to serialize the MIDI port in the following cases:
* We are not in song saving mode, i.e. we are in the state that this issue is about, e.g. cloning.
* We save a song and the MIDI connections are not discarded.
Using boolean algebra these conditions can be simplified as seen in the changed statement.
* Fix mixer channel updates on solo/mute
Fix the update of the mixer channels whenever a channel is soloed or muted.
The solution is rather "brutal" as it updates all mixer channel views when one of the models changes.
Introduce private helper method `MixerView::updateAllMixerChannels`. It calls the `update` method on each `MixerChannelView` so that they can get repainted.
Call `updateAllMixerChannels` at the end of the existing method `toggledSolo`.
Introduce a new method `MixerView::toggledMute` which is called whenever the mute model of a channel changes. It also updates all mixer channels.
Fixes#7054.
* Improve mixer channel update for mute events
Improve the mixer channel update for mute events by not delegating to `MixerView` like for the solo case. Instead the `MixerChannelView` now has its own `toggledMute` slot which simply updates the widget on changes to the mute model.
Also fix `MixerChannelView::setChannelIndex` by disconnecting from the signals of the previous mixer channel and connecting to the signals for the new one.
Remove `toggledMute` from `MixerView`.
The solo implementation is kept as is because it also triggers changes to the core model. So the chain seems to be:
* Solo button clicked in mixer channel view
* Button changes solo model
* Solo model signals to mixer view which was connected via the mixer channel view
* Mixer view performs changes in the other core models
* All mixer channels are updated.
Are better chain would first update the core models and then update the GUI from the changes:
* Solo button clicked in mixer channel view
* Button changes solo model
* Solo model signals to core mixer, i.e. not a view!
* Mixer view performs changes in the other core models
* Changed models emit signal to GUI elements
* Revert "Improve mixer channel update for mute events"
This reverts commit ede65963ea.
* Add comment
After the revert done with commit the code is more consistent again but not in a good way. Hence a comment is added which indicates that an inprovement is needed.
* Abstract mixer retrieval
Abstract the retrieval of the mixer behind the new method `getMixer`. This is done in preparation for some dependency injection so that the `MixerView` does not have to ask the `Engine` for the mixer but gets it injected, a.k.a. the "Hollywood principle": "Don't call us, we'll call you."
It's called `getMixer` and not just mixer because it allows for locale variables to be called `mixer` without confusing it with the method.
* Let MixerView connect directly to models
Let the `MixerView` connect directly to the solo and mute models it is connected with.
Remove the connections that are made in `MixerChannelView` which acted as a proxy which only complicated things.
Add `connectToSoloAndMute` which connects the `MixerView` to the solo and mute models of a given channel. Call it whenever a new channel is created.
Add `disconnectFromSoloAndMute` which disconnects the `MixerView` from the solo and mute models of a given channel. Call it when a channel is deleted.
* Code cleanup
Cleanup code related to the creation of the master channel view.
* Inject the Mixer into the MixerView
Inject the `Mixer` into the `MixerView` via the constructor. This makes it more explicit that the `Mixer` is the model of the view. It also implements the "Dependency Inversion Principle" in that the `MIxerView` does not have to ask the `Engine` for the `Mixer` anymore.
The current changes should be safe in that the `Mixer` instance is static and does not change.
* Fix connections on song load
Disconnect and reconnect in `MixerView::refreshDisplay` which is called when a song is loaded.
Caused by not calling `Engine::destroy`, as well as creating tracks/clips on the heap and not freeing the memory at the end of the test.
Instead of creating tracks/clips on the heap, they are now made on the stack, similar to how the surrounding tests create its objects.
Reduce code repetition in `MixerChannelView` by introducing methods that:
* Retrieve the `MixerChannel` that's associated with the view
* Check if the associated channel is the master channel
This abstracts some functionality and also reduces direct usage of the variable `m_channelIndex`.
* set win32 flag
* added mingw too to win32 flag + dom's suggestions
* revert unnecessary changes i made.
* simplify msys linker flag condition
* removed extra whitespace
* whitespace change 2
Fix a crash that occurs when songs are loaded after each other. The crash only occurs if the "participating" songs have at least one other channel besides the master channel.
The crash occurred because the `MixerChannelViews` were not really deleted in `MixerView::refreshDisplay`. As a consequence the parent child relationship was still given between the `MixerView` and the `MixerChannelView`. When a song was loaded the event queue was evaluated which in turn resulted in the method `Fader::knobPosY` being called on a `Fader` which did not have a model anymore.
Fixes#7046.
* 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