Moves the confirmation to remove mixer channels outside of `MixerView::deleteChannel` and into `MixerChannelView::removeChannel`. This is so that the confirmation only applies when the user uses the context menu to remove a channel, which is important since no confirmation should apply when, for example, the mixer view is cleared with calls to `MixerView::clear`.
* 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.
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>
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.
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.
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.
# Extend TabWidget's style sheet options
Extend the `TabWidget` class so that the text color of the selected tab
can be set in the style sheet. Adjust the paint method to make use of
the new property.
Adjust the default style sheet as follows:
* Background color of the selected tab is the green of the knobs
* Text color of the selected tab is full on white
Adjust the classic style sheet in such a way that nothing changes, i.e.
the text colors of the selected tab and the other ones are the same.
# Code review style changes
Completely adjust the code style of TabWidget:
* Pointer/reference close to type
* Remove underscores from parameter names
* Remove spaces from parentheses
* Add space after if and for statements
# Remove repeated iterator dereferences
Remove repeated iterator dereferences by introducing variables with speaking names.
Fixes#6730.
Use Qt layouts for the mixer channels. These changes will enable several other improvements, like for example making the mixer and faders resizable, adding peak indicators, etc.
This is a squash commit which consists of the following individual commits:
* Remove extra transparency in send/receive arrows
The extra transparency was conflicting with the positioning of
the arrows in the layout
* Begin reimplementing MixerChannelView
MixerChannelView is now a combination of the
MixerLine with the previous MixerChannelView
* Adjust SendButtonIndicator to use MixerChannelView
* Remove MixerLine
- Move MixerChannelView into src/gui
* Remove MixerView::MixerChannelView
* Remove header of MixerLine
* Change MixerView.h to use MixerChannelView
Change MixerView.h to use MixerChannelView rather than MixerLine
Also do some cleanup, such as removing an unused forward declaration
of QButtonGroup
* Create EffectRackView
+ Set height of sizeHint() using MIXER_CHANNEL_HEIGHT (287)
* Remove include of MixerLine
- Include MixerChannelView
* Phase 1: Adjust MixerView to use new MixerChannelView
* Move children wigets into header file
* Phase 2: Adjust MixerView to use new MixerChannelView
* Phase 3: Adjust MixerView to use new MixerChannelView
* Phase 4: Adjust MixerView to use new MixerChannelView
* Phase 5: Adjust MixerView to use new MixerChannelView
* Phase 5: Adjust MixerView to use new MixerChannelView
* Remove places where MixerChannelView is being deleted
Before, MixerChannelView was not inherited by QWidget,
meaning it could not have a parent and had to be deleted
when necessary. Since the MixerView owns the
new MixerChannelView, this is no longer necessary.
* Replace MixerLine with MixerChannelView
- Include MixerChannelView in MixerView
* Replace setCurrentMixerLine calls with setCurrentMixerChannel around codebase
* Add event handlers in MixerChannelView
* Implement MixerChannelView::eventFilter
* Update theme styles to use MixerChannelView
* Add QColor properties from style
- Set the Qt::WA_StyledBackground attribute on
* Add effect rack to rack layout when adding channel
* Set size for MixerChannelView
- Change nullptr to this for certain widgets
- Some custom widgets may expect there to be a parent
- Add spacing in channel layout
- Increase size of mixer channel
* Retain size when widgets are hidden
* Implement paintEvent
- Rename states in SendReceiveState
* Implement send/receive arrow toggling
- Make maxTextHeight constexpr in elideName
- Remove background changing on mouse press
(is now handled in paintEvent)
* Implement renaming mixer channels
* Implement color functions
* Implement channel moving/removing functions
* Do some cleanup
Not sure if that connection with the mute model was needed, but removing
it did not seem to introduce any issues.
* Include cassert
* Replace references to MixerLine with MixerChannelView
* Reduce height
+ Make m_renameLineEdit transparent
+ Retain size when LCD is hidden
+ Remove stretch after renameLineEdit in layout
* Remove trailing whitespace
* Make m_renameLineEdit read only
+ Transpose m_renameLineEditView rectangle (with 5px offset)
* Set spacing in channel layout back to 0
* Remove sizeHint override and constant size
* Use sizeHint for mixerChannelSize
+ Leave auto fill background to false in MixerChannelView
+ Only set width for EffectRackView
* Set margins to 4 on all sides in MixerChannelView
* Move solo and mute closer to each other
Move the solo and mute buttons closer to each other in the mixer channels.
Technically this is accomplished by putting them into their own layout with minimal margins and spacing.
* Fixes for CodeFactor
* Code review changes
Mostly whitespace and formatting changes: remove tabs, remove spaces in parameter lists, remove underscores from parameter names.
Some lines have been shortened by introducing intermediate variables, e.g. in `MixerChannelView`.
`MixerView` has many changes but only related to whitespace. Spaces have been introduced for if and for statements. Whitespace at round braces has been removed everywhere in the implementation file even if a line was not touched by the intial changes.
Remove duplicate forward declaration of `MixerChannelView`.
* Adjust parameter order in MixerChannelView's constructor
Make the parent `QWidget` the first parameter as it is a Qt convention. The default parameter had to be removed due to this.
* Move styling of rename line edit into style sheets
Move the style of the `QGraphicsView` for the rename line edit from the code into the style sheets of the default and classic theme.
* More code review changes
Fix spaces between types and references/pointers, e.g. use `const QBrush& c` instead of `const QBrush & c`.
Remove underscores from parameter names.
Remove spaces near parentheses.
Replace tabs with spaces.
Introduce intermediate variable to resolve "hanging" + operator.
Replace the connection for the periodic fader updates with one that uses function pointers instead of `SIGNAL` and `SLOT`.
---------
Co-authored-by: Michael Gregorius <michael.gregorius.git@arcor.de>
* 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>
* Replace knobFModel with std::vector
* Create QPixmap's on the stack
* Assign parent for QGraphicsScene
A call to QGraphicsView::setScene does not make
the view take ownership of the scene.
* Do not allocate QList on the heap
* Use static QPixmap's
The QPixmap's need to be created within the constructor, and not outside
where they are defined, since it can't find them otherwise.
I'm not too sure why.
* Clear m_vi2->knobFModel in destructor
* Use local static QPixmap's
* Do not allocate QPixmap with new in AudioFileProcessor
* Do not allocate QPixmap with new in Nes
* Do not allocate QPixmap with new in Organic
* Do not allocate QPixmap with new in SaControlsDialog
* Do not allocate QPixmap with new in Vestige
* Do not allocate QPixmap with new for FileBrowser
* Do not allocate QPixmap with new in MixerLine
* Do not allocate QPixmap with new in SendButtonIndicator
* Do not allocate QPixmap with new in AutomationClipView
* Do not allocate QPixmap with new in MidiClipView
* Do not allocate QPixmap with new in AutomationEditor
* Do not allocate QPixmap with new in PianoRoll
* Do not allocate QPixmap with new in TimeLineWidget
* Do not allocate QPixmap with new in EnvelopeAndLfoView
* Do not allocate QPixmap with new in PianoView
* Do not allocate QPixmap with new in ComboBox
* Do not allocate QPixmap with new in Fader
* Do not allocate QPixmap with new for LcdWidget
* Do not allocate QPixmap with new for LedCheckbox
* Use m_ as prefix for members
* Use uniform initialization
I already started using uniform initialization for the QPixmap changes
for some reason, so I'm finishing that up.
* Uniform initiaization
* And then he realized he was making copies...
* Do not call QPixmap copy constructor
* Do not call QPixmap copy constructor in SaControlsDialog
* Do not make pixmap's static for Lcd's and Led's
* Initialize pixmaps in-class
* Fix few mistakes and formatting
Improves performance when searching in the file browser (confirmed with profiling using KCacheGrind), adds a search indicator at the bottom to let the user know a search is in progress, blacklists unnecessary system directories (speeding up both the search speed and potentially load times as well by reducing the number of filesystem entries to consider), and fixes an issue that causes not all of the search results to appear.
* Initial Commit
Starts implementing Note Types. The two available types are
RegularNote and StepNote. PianoRoll now paints the color with a
different color for StepNotes. Pattern::addStep now sets the type of the
note to StepNote.
Negative size is still used to signal a step note.
* Update Pattern.cpp to account for the Note::Type
Updates the methods noteAtStep(), addStepNote() and checkType()
from Pattern.cpp to account for the note type and not the note length.
* Update PatternView::paintEvent to draw step notes
PatternView::paintEvent now draws the pattern if the pattern
type is BeatPattern and TCOs aren't fixed (Song Editor). Color used is
still the BeatPattern color (grey) and the conditional doesn't look very
nice and can be improved.
Pattern::beatPatternLength was also updated so it accounts for
the note type not note length. Review this method, as it looks a bit
weird (particularly the second conditional).
* Implements StepNotes setting a NPH with 0 frames
Now, instead of TimePos returning 0 for negative lengths, we
create a NotePlayHandle with 0 frames when the note type is StepNote on
InstrumentTrack::play.
* Improves PatternView::paintEvent conditional
Improves a conditional inside PatternView::paintEvent by
reversing the order in which they are executed.
* Adds upgrade method for backwards compatibility
Adds an upgrade method that converts notes with negative length
to StepNotes, so old projects can be loaded properly.
Explicitly set the Note::RegularNote value as 0.
Make the default "type" value "0", so notes without a type are
loaded as RegularNotes.
* Addresses Veratil's review
- Changes "addStepNote" so "checkType" isn't called twice in a
row.
- Changes style on a one line conditional.
* Uses ternary expression on statement
Reduces number of lines by using ternary expression.
* Addresses PR review (sakertooth)
- Changes class setter to inline
- Uses enum class instead of enum
- Uses auto and const where appropriate
* Finished changes from review (sakertooth)
- Used std::max instead of qMax
- Fixed style on lines changed in the PR
* Uses std::find_if to save codelines
As suggested by sakertooth, by using std::find_if we are able to
simplify the checkType method to two lines.
* Addresses review from sakertooth
- Reverts m_detuning in-class initialization
- Removes testing warning
- Removes unnecessary comment
* Addresses DomClark's review
- Rename the Note Types enum to avoid redundancy
- Uses std::all_of instead of std::find_if on MidiClip checkType
- Rewrites addStepNote so it sets the note type before adding it
to the clip, avoiding having to manually change the type of the clip
after adding the note
* Updates MidiExport to use Note Types
- Now MidiExport is updated to use note types instead of relying
on negative length notes.
- For that change it was necessary to find a way of letting
MidiExport know how long step notes should be. The solution found was to
add an attribute to the Instrument XML called "beatlen", which would
hold the number of frames of the instrument's beat. That would be
converted to ticks, so we could calculate how long the MIDI notes would
have to be to play the whole step note. If the attribute was not found,
the default value of 16 ticks would be used as a length of step notes,
as a fallback.
* Fixes ambiguity on enum usage
Due to changes in the name of enum classes, there was an
ambiguity caused in NotePlayHandle.cpp. That was fixed.
* Addresses new code reviews
- Addresses code review from PhysSong and Messmerd
* Fixes note drawing on Song Editor
- Notes were not being draw on the song editor for BeatClips.
This commit fixes this.
* Adds cassert header to TimePos.cpp
- Adds header to use assert() on TimePos.cpp
* Apply suggestions from code review
Fixes style on some lines
Co-authored-by: Dalton Messmer <33463986+messmerd@users.noreply.github.com>
* Reverts some changes on MidiExport
- Some changes were reverted on MidiExport and InstrumentTrack.
We were storing the beat length on the XML of Instrument Tracks, but in
reality the beat length is a per note attribute, and some instruments
could run into a segmentation fault when calling beat length without a
NotePlayHandle (i.e.: AFP). Because of that I reverted this change, so
the beat length is not stored on the XML anymore, and instead we have a
magic number on the MidiExport class that holds a default beat length
which is actually an upper limit for the MIDI notes of step notes. In
the future we can improve this by finding a way to store the beat length
on the note class to use it instead. The MidiExport logic is not
worsened at all because previously the beat length wasn't even
considered during export (it was actually improved making the exported
notes extend until the next one instead of cutting shorter).
* Fix the order of included files
---------
Co-authored-by: Dalton Messmer <33463986+messmerd@users.noreply.github.com>
The revamp consists of one lock. When the audio thread needs to render audio or another thread wants to run a change, acquiring the lock grants mutual exclusion to do one of the two. The intention is that this will provide stronger guarantees that changes do not run concurrently with the audio thread, as well as having the synchronization mechanism itself be free of data races (verified with TSan).
* Added floating-point vorbis BPM tags to files in lmms/data/samples/beats
* Added rounded BPM to filenames, surrounded by square brackets and separated from the rest of the filename by an underscore
This fixes at least three issues:
* Help window is not synched with window manager's `X`-button
* Help window is not being closed on track destruction or on closing the plugin window
* Trims help window strings and force-adds a newline, because `QLabel::sizeHint` sometimes computes too small values. Now, together with #6956, all help windows fit their strings. Some help windows are too large by one line, but this seems better than forcing the user to resize them if they are too small by one line.
Before this commit, on creation, `SubWindow` gets resized to exactly the
children's `sizeHint`. This makes the child too small, since the
`SubWindow` already contains a title bar and borders.
With this commit, the `SubWindow` is calculated such that after
rendering, the child window gets exactly the `size` that its `sizeHint`
has previously suggested.
Most of LMMS widgets are not resizable, but the Lv2 help window is a
good example to test this out. The help windows now in most cases
contain enough space to fit the help text. In some cases, it still does
not fit, though debug prints show that the `size` matches the
`sizeHint`.
This PR is a about reloading an `Lv2Proc`, e.g. in case of a sample rate
change.
Prior to this PR, #6419 handled this by first saving the models into
XML, then destroying and re-initializing the whole `Lv2Proc` and finally
reloading the saved XML. However, #6786 shows that the automation is not
properly restored in such a case.
This PR thus attempts to not destroy the automatable models, just
everything else. This is done by moving `Lv2Proc::createPorts` into the
CTOR before calling `Lv2Proc::initPlugin`, which makes `initPlugin()`
and `shutdownPlugin()` proper inverses of each other (note that in jalv,
the ports are also created before the features are). The new class
`Lv2ProcSuspender` adds an RAII interface for reloading the `Lv2Proc`.
Note that another, possibly more clean approach would be to separate the
features and the plugin from the models ("controls"), to then only
destroy the features and the plugin. This could be done by having
`Lv2Effect` contain an `Lv2Proc` and `Lv2FxControls` contain an
`Lv2ProcControls`. Then the effect classes are the usual way round, and
you still maintain the separation between processor and controls in the
core LV2 code. (Similarly for the instrument, except we don't have a
processor/control split for instruments, so an instance of each class
would be contained within the same instrument instance.) - Thanks for
this proposal to @DomClark .