-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Fix audio resampling functionality #7858
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
166 commits
Select commit
Hold shift + click to select a range
dda8799
Change to callback API
sakertooth 05f7e39
Use SampleFrame abstraction in AudioResampler
sakertooth eded00a
Remove advance call
sakertooth bf219e0
Simplfy AudioResampler API, handle incomplete reads of write buffer
sakertooth a651add
Enforce a channel count of 2
sakertooth e897e94
Fix calculation of resample ratio
sakertooth 36a561d
Removed unused include
sakertooth fb7dbac
Fix freeze when reaching the end of sample
sakertooth 9c2a999
Persist write buffer across resample calls
sakertooth 2ab0d8a
Not sure I want do to that here, maybe in another PR
sakertooth 74cd449
Update copyright
sakertooth 33bf943
Allow for AudioResampler to be moved, add more docs
sakertooth afeb45d
Remove bounds check in Sample::play
sakertooth 62adb98
Return true or false from resample call
sakertooth 5ca52ab
Fix signedness issues and others
sakertooth e7d4c51
Make resampler API more flexible
sakertooth f7abcf8
Add BipBuffer
sakertooth 0ccac34
Use BipBuffer
sakertooth f76a7c8
Fix BipBuffer issues
sakertooth 127f511
Make BipBuffer atomic
sakertooth c29a96c
Keep it simple
sakertooth 0ede71a
Oops
sakertooth c139088
Simplify some stuff
sakertooth 139155e
Pass in ratio directly
sakertooth 8957bd4
Use Sample for playback in SlicerT
sakertooth 1987df3
Clean up some stuff in Sample
sakertooth c6a683e
Remove TODO comment
sakertooth 8d6f2e3
Fix Patman build
sakertooth e5eb92d
Handle resampling errors
sakertooth c806208
Use AudioResampler in Sf2Player
sakertooth f985136
Fix signed comparison issue
sakertooth 126c5c7
Remove write callback
sakertooth a1bff38
Update docs
sakertooth d248adb
Fix SlicerT crash
sakertooth 5ed9184
Revert "Remove write callback"
sakertooth 27f8473
Redesign resampler interface again
sakertooth 54072c0
Enforce that destination buffer must hold all of source buffer when r…
sakertooth fe9cd1c
Add WriteCallbackResult, apply fixes
sakertooth e58b72a
Fix API issues and bugs
sakertooth b5160f9
Use AudioResampler in Watsyn
sakertooth 7993dd0
Use AudioResampler in GigPlayer
sakertooth 040a01f
Use AudioResampler in LadspaEffect
sakertooth e8ff4f1
Remove use of buffer margins
sakertooth 33df5be
Include array header
sakertooth b2ad621
Enforce that the destination buffer contains all resampled audio
sakertooth 7edbba6
Merge remote-tracking branch 'upstream/master' into fix-resampling
sakertooth 06b5306
Merge remote-tracking branch 'upstream' into fix-resampling
sakertooth f7de794
Simplify interface
sakertooth d59f094
Use correct type
sakertooth 64d74d0
Fix subtle issues
sakertooth a791218
Merge remote-tracking branch 'upstream' into fix-resampling
sakertooth 2e6d44e
Return resampling results
sakertooth 013f59b
Revert "Return resampling results"
sakertooth bfae743
Return resampling results
sakertooth f717272
Fix GigPlayer
sakertooth fe3b5df
Scope write callback lambdas
sakertooth 1057df5
Remove TODO comment
sakertooth 1165287
Revert "Return resampling results"
sakertooth de1c2a5
Use write callback in Watsyn
sakertooth a01e113
Always use the write callback approach
sakertooth 834c3e7
Stop trying to resample if no input frames were written
sakertooth 467fd27
Dont try to resample within the effect chain for LADSPA
sakertooth 6d21482
Remove resampler in LADSPA
sakertooth 3dbc9be
Remove unused errorDescription function
sakertooth 72598fc
Allocate internal callback buffer on the heap
sakertooth a9fdaf0
Remove channel parameter in write callback
sakertooth 81f488d
Rename resampleCallback to inputCallback
sakertooth cda43b9
Return bool to signify if the destination buffer is completely filled
sakertooth 0b24801
Fill remaining buffer with silence when no more input frames can be g…
sakertooth 0c25424
Merge remote-tracking branch 'upstream' into fix-resampling
sakertooth ca8bdc9
Improve AudioResampler API
sakertooth a853777
Replace conditional with assert, check for error on calls to fluid_sy…
sakertooth 7989165
Fix bug with GigPlayer
sakertooth 05e8213
Remove AudioResampler::Result, return only what is necessary
sakertooth e13b457
Enforce proper channel counts
sakertooth 1ecee14
Fix signedness comparison
sakertooth a99a8d6
Fix Sample playback start position bug
sakertooth e58889f
Fix signed potential loss of data warning
sakertooth 6227be8
Go back to using conditional in Sf2Player
sakertooth 67918ee
Use generic InterleavedAudioBufferView struct
sakertooth c2e3765
Add some documentation
sakertooth bfb7c82
Fix GigPlayer crash/audio glitch
sakertooth 43e4228
Fix Sf2Player crash/audio glitch
sakertooth b5b3654
Merge remote-tracking branch 'upstream' into fix-resampling
sakertooth 6c17316
Use enum class for interpolation modes
sakertooth c125c0f
Merge remote-tracking branch 'upstream' into fix-resampling
sakertooth 3522954
Use messmerd's audio buffer view patch
sakertooth 06435e6
Use types from LmmsTypes
sakertooth 8d6e78a
Add LMMS_EXPORT to Mode
sakertooth c09f8d9
Set item data instead of using current index (export interpolation co…
sakertooth 1671d8b
Simplify AudioResampler interface, keep it more bare bones, dont allo…
sakertooth a909f69
Update documentation
sakertooth 337e18a
Assign to freq_factor
sakertooth 24de727
Fix GigPlayer
sakertooth 72bf896
Apply sample rate conversion in Sample
sakertooth 143822a
Cast to double
sakertooth bc7432b
Use aggregate initialization
sakertooth 5770b7c
Remove LMMS_EXPORT from AudioResampler::Mode (ignored?)
sakertooth 659d7a4
Make numFramesMixed of type f_cnt_t
sakertooth da72c85
Delete copy constructors again to fix builds
sakertooth 8e42f7c
Remove m_interpolation variable
sakertooth c49a2a4
Remove unused include
sakertooth c2bed13
Remove end of input flag
sakertooth a2a67e0
Advance on calls to process, remove advance functions
sakertooth 81b95d1
Add function overload for setting the resampling ratio with input and…
sakertooth 1cdee38
Do not have input and outputs in getters and setters
sakertooth d30c0a4
Implement AudioResamplerStream
sakertooth 4a0d3f9
Advance Gig playback stream when resampling
sakertooth 5ae8b53
Remove max sample rate logic from LADSPA
sakertooth 9e0ba4b
Create new resampler when reloading Sf2 instrument
sakertooth 332f67a
Try to fix Mac builds
sakertooth c532eb0
Dont create resampler when reloading Sf2, performance issue
sakertooth 2d6fef4
Add constructor to qualitySettings
sakertooth a88942e
And new line at the end of AudioResamplerStream.h
sakertooth 6c81eb2
Add reset function
sakertooth b5fbee3
Reset resmplaer state in Watsyn on calls to srccpy
sakertooth 75630cc
Simplify source index calculation in Watsyn
sakertooth 529bf3f
Add flush function, remove endOfInput flag
sakertooth c561e8d
Remove flush function
sakertooth e0310fa
Move AudioResamplerSteam to AudioResampler::Stream
sakertooth 3ddfdf2
Take into account the frequency when resampling in Sample
sakertooth 6a026af
Rewrite resampling loop to fix bugs
sakertooth 007eddf
Add subspan function for interleaved views
sakertooth 94dd106
Update subspan function
sakertooth 69863ab
Merge AudioResampler::Stream functionality into AudioResampler
sakertooth 826693d
Spruce up documentation a bit
sakertooth 3927b17
Make AudioResampler stateless again
sakertooth fb2fa16
Stop resampling loop if no input data
sakertooth 883ed0d
Add TODO comments
sakertooth d43d09a
Merge remote-tracking branch 'upstream' into fix-resampling
sakertooth 7e4230f
Merge remote-tracking branch 'upstream' into fix-resampling
sakertooth 841b78d
Use emplace_back
sakertooth 2805834
Remove my subspan function
sakertooth 44b9011
Simplify Sf2 input handling
sakertooth b906420
Use std::vector instead of QList for storing Gig samples
sakertooth 84d455d
Use only one call to setRatio in Sample
sakertooth c7d8448
Handle m_ratio and m_error in move constructor and move assignment op…
sakertooth 660cbe1
Use type erasure to make libsamplerate an implementation detail
sakertooth d79c6a2
Store std::unique_ptr, remove the user-defined special member functions
sakertooth e95da7f
Restructure audio pipeline in GigPlayer a bit
sakertooth 1c5d41c
Simplify mix loop
sakertooth 6303c52
Maybe will fix MinGW (??)
sakertooth 18330a0
Consistency for now
sakertooth 29501e3
Use brace initialization
sakertooth 3920872
Add BipBuffer
sakertooth c22e3bc
Default BipBuffer capacity to DEFAULT_BUFFER_SIZE
sakertooth e577301
Add empty/full functions, update docs
sakertooth 0008801
Revert use of std::clamp to if condition
sakertooth a1b9617
Update BipBuffer implementation
sakertooth e6b8c06
Use BipBuffer
sakertooth 8d26258
Add safeguards in BipBuffer
sakertooth e23549d
Revert "Add safeguards in BipBuffer"
sakertooth 5a0b737
Rename BipBuffer functions
sakertooth b343ac4
Remove quality settings (interpolation mode)
sakertooth 0e5c462
Fix a few things
sakertooth 102c45f
Only set interpolation mode in Sf2 if sample rates differ
sakertooth 0a496c5
Move converterType function into anonymous namespace
sakertooth 7c3f4ad
Remove BipBuffer
sakertooth 5d8d212
Fix signed comparison issue
sakertooth ec4fc4c
Use std::span
sakertooth 6334d2d
Update copyright
sakertooth caf0e09
Remove redundant assignment to nullptr
sakertooth a5b077a
Use m_ prefix
sakertooth 4bd8098
Remove defaulted Sample destructor
sakertooth ae03647
Do not pass detuning info for frame index in Patman's playback state
sakertooth 6cefb75
Use nested anonymous namespace
sakertooth File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,7 @@ | ||
| /* | ||
| * AudioResampler.h - wrapper around libsamplerate | ||
| * AudioResampler.h | ||
| * | ||
| * Copyright (c) 2023 saker <[email protected]> | ||
| * Copyright (c) 2025 saker <[email protected]> | ||
| * | ||
| * This file is part of LMMS - https://lmms.io | ||
| * | ||
|
|
@@ -25,41 +25,104 @@ | |
| #ifndef LMMS_AUDIO_RESAMPLER_H | ||
| #define LMMS_AUDIO_RESAMPLER_H | ||
|
|
||
| #include <samplerate.h> | ||
|
|
||
| #include <memory> | ||
| #include "AudioBufferView.h" | ||
| #include "lmms_export.h" | ||
|
|
||
| namespace lmms { | ||
|
|
||
| /** | ||
| * @class AudioResampler | ||
| * @brief A utility class for resampling interleaved audio buffers using various resampling algorithms. | ||
| * | ||
| * This class provides support for zero-order hold, linear, and several levels of sinc-based resampling. | ||
| */ | ||
| class LMMS_EXPORT AudioResampler | ||
| { | ||
| public: | ||
| struct ProcessResult | ||
| /** | ||
| * @enum Mode | ||
| * @brief Defines the resampling method to use. | ||
| */ | ||
| enum class Mode | ||
| { | ||
| ZOH, //!< Zero Order Hold (nearest-neighbor) interpolation. | ||
| Linear, //!< Linear interpolation. | ||
| SincFastest, //!< Fastest sinc-based resampling. | ||
| SincMedium, //!< Medium quality sinc-based resampling. | ||
| SincBest //!< Highest quality sinc-based resampling. | ||
| }; | ||
|
|
||
| /** | ||
| * @struct Result | ||
| * @brief Result of a resampling operation. | ||
| */ | ||
| struct Result | ||
| { | ||
| int error; | ||
| long inputFramesUsed; | ||
| long outputFramesGenerated; | ||
| f_cnt_t inputFramesUsed; //!< The number of input frames used during processing. | ||
| f_cnt_t outputFramesGenerated; //!< The number of output frames generated during processing. | ||
| }; | ||
|
|
||
| AudioResampler(int interpolationMode, int channels); | ||
| AudioResampler(const AudioResampler&) = delete; | ||
| AudioResampler(AudioResampler&&) = delete; | ||
| ~AudioResampler(); | ||
| /** | ||
| * @brief Constructs an `AudioResampler` instance. | ||
| * @param mode The resampling mode to use. | ||
| * @param channels Number of audio channels. Defaults to `2` (stereo). | ||
| */ | ||
| AudioResampler(Mode mode, ch_cnt_t channels = 2); | ||
|
|
||
| AudioResampler& operator=(const AudioResampler&) = delete; | ||
| AudioResampler& operator=(AudioResampler&&) = delete; | ||
| /** | ||
| * @brief Process a block of interleaved audio input from `input` and resample it into `output`. | ||
| * | ||
| * @param input The interleaved audio input. | ||
| * @param output The interleaved audio output. | ||
| * | ||
| * @throws `std::invalid_argument` if a channel mismatch has been detected. | ||
| * @throws `std::runtime_error` if the resampling process has failed. | ||
| * | ||
| * @remark This utility class does not cache the input and output buffers, making it stateless. In other words, | ||
| * `input` is directly resampled into the `output`. | ||
| * | ||
| * @returns the result of the resampling process. See @ref Result for more details. | ||
| */ | ||
| [[nodiscard]] auto process(InterleavedBufferView<const float> input, InterleavedBufferView<float> output) -> Result; | ||
|
|
||
| auto resample(const float* in, long inputFrames, float* out, long outputFrames, double ratio) -> ProcessResult; | ||
| auto interpolationMode() const -> int { return m_interpolationMode; } | ||
| auto channels() const -> int { return m_channels; } | ||
| void setRatio(double ratio); | ||
| /** | ||
| * @brief Resets the internal resampler state. | ||
| * Useful when working with unreleated pieces of audio. | ||
| */ | ||
| void reset(); | ||
|
|
||
| /** | ||
| * @brief Sets the resampling ratio to `ratio`. | ||
| * @param ratio Output sample rate divided by input sample rate. | ||
| */ | ||
| void setRatio(double ratio) { m_ratio = ratio; } | ||
|
|
||
| /** | ||
| * @brief Sets the resampling ratio to `output / input`. | ||
| * @param input Input sample rate. | ||
| * @param output Output sample rate. | ||
| */ | ||
| void setRatio(sample_rate_t input, sample_rate_t output) { m_ratio = static_cast<double>(output) / input; } | ||
|
|
||
| //! @returns the resampling ratio. | ||
| auto ratio() const -> double { return m_ratio; } | ||
|
|
||
| //! @returns the number of channels expected by the resampler. | ||
| auto channels() const -> ch_cnt_t { return m_channels; } | ||
|
|
||
| //! @returns the interpolation mode used by this resampler. | ||
| auto mode() const -> Mode { return m_mode; } | ||
|
|
||
| private: | ||
| int m_interpolationMode = -1; | ||
| int m_channels = 0; | ||
| struct LMMS_EXPORT StateDeleter { void operator()(void* state); }; | ||
| std::unique_ptr<void, StateDeleter> m_state; | ||
| Mode m_mode; | ||
| ch_cnt_t m_channels = 0; | ||
| double m_ratio = 1.0; | ||
| int m_error = 0; | ||
| SRC_STATE* m_state = nullptr; | ||
| }; | ||
|
|
||
| } // namespace lmms | ||
|
|
||
| #endif // LMMS_AUDIO_RESAMPLER_H | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.