Skip to content
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

Add support for multi-channel plugins #7459

Open
wants to merge 68 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 55 commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
93884a2
Add PluginPortConfig class
messmerd May 8, 2024
f1f1010
Avoid misleading types and weird casts
messmerd May 8, 2024
c78c17f
Use PluginPortConfig for mono VSTs
messmerd May 8, 2024
4da60af
Refactor; Fix automation clip tooltip
messmerd Jun 16, 2024
798e088
Begin pin connector implementation (WIP)
messmerd Aug 11, 2024
af4d6b3
Loading/saving (WIP)
messmerd Aug 11, 2024
aafe41c
More efficient loading
messmerd Aug 11, 2024
360eca6
Use new routing methods (WIP)
messmerd Aug 11, 2024
7b7f674
Progress (WIP)
messmerd Aug 12, 2024
1568d3a
Merge branch 'master' into pin-connector
messmerd Aug 12, 2024
5f31c04
Fix up post-merge (WIP)
messmerd Aug 12, 2024
853d80c
Fix crash
messmerd Aug 14, 2024
7935718
Begin implementing PluginPinConnectorView
messmerd Aug 14, 2024
b3ad72a
Progress (WIP)
messmerd Aug 14, 2024
b55bdec
Fix pin icon while dragging
messmerd Aug 14, 2024
bda93bc
More progress
messmerd Aug 15, 2024
15f395e
Draw plugin channel text
messmerd Aug 15, 2024
8d2acad
Fix Linux build
messmerd Aug 15, 2024
a00cdba
Some refactoring
messmerd Aug 16, 2024
c98353f
Fix build
messmerd Aug 16, 2024
774e3b6
Introduce MatrixView class
messmerd Aug 17, 2024
e768a58
Use layouts
messmerd Aug 17, 2024
2ee2c08
Make PluginPinConnector::Matrix a struct; Add tooltips
messmerd Aug 17, 2024
8445f2c
Set model display names
messmerd Aug 17, 2024
ecc6318
Fix a display bug
messmerd Aug 17, 2024
a317e16
Remove some unused code
messmerd Aug 17, 2024
2571547
Fix crash when reloading project with pin connector open
messmerd Aug 17, 2024
ada15d3
Fix miscalculation in mousePressEvent
messmerd Aug 18, 2024
a308725
Better pin connector button text; Better naming and comments
messmerd Aug 25, 2024
09eb59f
Use pointing hand cursor when hovering over cells
messmerd Aug 25, 2024
f6910c6
Make routing methods const
messmerd Sep 14, 2024
ba3ffc6
Improve routing normalization
messmerd Sep 14, 2024
af5c16b
Use bitwise OR
messmerd Sep 14, 2024
32557d4
Move some pin connector methods into Matrix
messmerd Sep 14, 2024
1716186
Use `const float*` for process's in buffer
messmerd Sep 14, 2024
23fd48b
Rename `m_trackChannelsUsed` to `m_trackChannelsUpperBound`
messmerd Sep 21, 2024
089ffb4
Merge branch 'master' into pin-connector
messmerd Sep 21, 2024
62efd0e
Various changes
messmerd Sep 23, 2024
b7883f1
Use `MAXIMUM_BUFFER_SIZE`
messmerd Sep 23, 2024
bd404df
Revert strongly typed sample types
messmerd Oct 16, 2024
dcf1fc9
Minor optimization in `mixInputs` lambda
messmerd Oct 16, 2024
f522c17
Merge branch 'master' into pin-connector
messmerd Nov 23, 2024
6e1d921
Pin connector refactor (#2)
messmerd Dec 14, 2024
d69c449
VST effect wet/dry mixing
messmerd Dec 14, 2024
afc24cc
Add pin connector button to EffectView
messmerd Dec 15, 2024
414e7c9
Remove old pin connector button from VstEffectControls
messmerd Dec 15, 2024
a56520f
Update pin connector button's tooltip when channel count changes
messmerd Dec 15, 2024
a43e121
Fix default connections for instruments with sidechain inputs
messmerd Dec 15, 2024
9136b7d
Draw arrows in and out of plugin channels; Simplifications
messmerd Dec 15, 2024
d4b9b43
Add pluginBuffersChange signal; improve error handling
messmerd Dec 17, 2024
5bd1ec3
Merge branch 'master' into pin-connector
messmerd Dec 22, 2024
2a271fd
Fix VST silent output
messmerd Dec 24, 2024
b81546a
Fix isMidiBased
messmerd Dec 30, 2024
36c99d9
Rename classes
messmerd Dec 31, 2024
3661bbd
Address review comments
messmerd Dec 31, 2024
262e540
Fix crash when loading VST instrument as a VST effect
messmerd Jan 8, 2025
b34df28
Use "summing" behavior rather than "averaging"
messmerd Jan 12, 2025
eadeabf
Plugin audio ports (#3)
messmerd Jan 29, 2025
b96b2f9
Merge branch 'master' into pin-connector
messmerd Jan 29, 2025
15b15cf
Add pin connector button for all instruments
messmerd Jan 31, 2025
0107d60
Include memory header
messmerd Jan 31, 2025
50dc34d
Merge branch 'master' into pin-connector
messmerd Feb 5, 2025
11aa3fa
Use std::span
messmerd Feb 5, 2025
b2b8b3b
Fix saving and loading
messmerd Feb 5, 2025
c132756
Use `@tparam` instead of `@param`
messmerd Feb 8, 2025
28aca19
Pass audio port type as template template parameter
messmerd Feb 9, 2025
f3a8b3f
Remove `CoreAudioData` and `CoreAudioDataMut`
messmerd Feb 9, 2025
b4736cc
Merge branch 'master' into pin-connector
messmerd Feb 9, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
201 changes: 201 additions & 0 deletions include/AudioData.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
/*
* AudioData.h - Audio data types
*
* Copyright (c) 2024 Dalton Messmer <messmer.dalton/at/gmail.com>
*
* This file is part of LMMS - https://lmms.io
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program (see COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
*/

#ifndef LMMS_AUDIO_DATA_H
#define LMMS_AUDIO_DATA_H

#include <cassert>
#include <type_traits>
Copy link
Contributor

@JohannesLorenz JohannesLorenz Dec 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR seems to have many useless includes. While many of them might be caused in the past, at least for those files where you touch the includes (or for all files that you touch?), they should be cleaned in this PR.

Checking for includes can be done as follows (I once need to set up a wiki page for this, or even integrate it):

  1. Run flags="include-what-you-use;-Xiwyu;--mapping_file=/usr/share/include-what-you-use/qt5_11.imp;-Xiwyu;--keep=*/xmmintrin.h;-Xiwyu;--keep=*/lmmsconfig.h;-Xiwyu;--keep=*/weak_libjack.h;-Xiwyu;--keep=*/sys/*;-Xiwyu;--keep=*/debug.h;-Xiwyu;--keep=*/SDL/*;-Xiwyu;--keep=*/alsa/*;-Xiwyu;--keep=*/FL/x.h;-Xiwyu;--keep=*/MidiApple.h;-Xiwyu;--keep=*/MidiWinMM.h;-Xiwyu;--keep=*/AudioSoundIo.h" (assuming you use Qt5, you are on Linux and the mapping file is correct)
  2. Run cmake -DCMAKE_C_INCLUDE_WHAT_YOU_USE="$flags" -DCMAKE_CXX_INCLUDE_WHAT_YOU_USE="$flags" ..
  3. Run make >make.txt 2>&1 (and wait a whole while, this can take half an hour)
  4. Copy the following script into your build dir and run it:
#!/bin/bash

cat make.txt |
awk '/should remove these lines:$/ {print; flag=1; next} /^The full include-list for/ {flag=0} flag && NF' | # print all from "should remove these lines" until "The full include list"
awk '/ should / {if(found) { found=0 } should=$LINE} /- .+/ {if(found==0) print should; found=1; print}' | # print only if at least one nonempty removal suggestion is found |
awk '/ should / {ignore=0} /globals.h should/ {ignore=1} (!ignore)' # ignore globals.h - this is just an example for zyn, you can use this for LMMS with other files

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One note about this: I plan to do a complete #include-cleanup on master. You can still do it hear, but you can also merge without this check to master and I will fix it there, anyways.


#include "lmms_basics.h"

namespace lmms
{

//! Conventions for passing audio data
enum class AudioDataLayout
{
/**
* Given:
* - N == Frame count
* - C == Number of channels
* - i == Sample index, where 0 <= i < N
* - `samples` has the type sample_t*
* - `samples` size == N * C
*/

/**
* Layout where the samples for each channel are interleaved.
* i.e. "LRLRLRLR"
*
* Samples for individual channels can be accessed like this:
* - Channel #0 samples: samples[C*i]
* - Channel #1 samples: samples[C*i + 1]
* - Channel #2 samples: samples[C*i + 2]
* - Channel #3 samples: samples[C*i + 3]
* - ...
*/
Interleaved,

/**
* Layout where all samples for a particular channel are grouped together.
* i.e. "LLLLRRRR"
*
* Samples for individual channels can be accessed like this:
* - Channel #0 samples: samples[i]
* - Channel #1 samples: samples[1*N + i]
* - Channel #2 samples: samples[2*N + i]
* - Channel #3 samples: samples[3*N + i]
* - ...
*/
Split
};


/**
* A simple type alias for floating point audio data types which documents the data layout.
*
* For example, `const InterleavedSampleType<sample_t>*` can be used as a replacement for `const sample_t*`
* parameters in order to document that the data layout of the audio is interleaved.
*
* NOTE: Can add support for integer sample types later
*/
template<AudioDataLayout layout, typename T, std::enable_if_t<std::is_floating_point_v<T>, bool> = true>
using SampleType = T;

template<typename T>
using SplitSampleType = SampleType<AudioDataLayout::Split, T>;

template<typename T>
using InterleavedSampleType = SampleType<AudioDataLayout::Interleaved, T>;


//! Use when the number of channels is not known at compile time
inline constexpr int DynamicChannelCount = -1;


/**
* Non-owning view for multi-channel "split" (non-interleaved) audio data
*
* TODO C++23: Use std::mdspan
*/
template<typename SampleT, int channelCount = DynamicChannelCount, typename = SplitSampleType<SampleT>>
class SplitAudioData
{
public:
SplitAudioData() = default;
SplitAudioData(const SplitAudioData&) = default;

/**
* `data` is a 2D array of channels to buffers:
* data[channels][frames]
* Each buffer contains `frames` frames.
*/
SplitAudioData(SplitSampleType<SampleT>* const* data, pi_ch_t channels, f_cnt_t frames)
: m_data{data}
, m_channels{channels}
, m_frames{frames}
{
assert(channelCount == DynamicChannelCount || channels == channelCount);
}

//! Contruct const from mutable
template<typename T = SampleT, std::enable_if_t<std::is_const_v<T>, bool> = true>
SplitAudioData(const SplitAudioData<std::remove_const_t<T>, channelCount>& other)
: m_data{other.data()}
, m_channels{other.channels()}
, m_frames{other.frames()}
{
}

/**
* Returns pointer to the buffer of a given channel.
* The size of the buffer is `frames()`.
*/
auto buffer(pi_ch_t channel) const -> SplitSampleType<SampleT>*
{
assert(channel < m_channels);
return m_data[channel];
}

template<pi_ch_t channel>
auto buffer() const -> SplitSampleType<SampleT>*
{
static_assert(channel != DynamicChannelCount);
static_assert(channel < channelCount);
return m_data[channel];
}

constexpr auto channels() const -> pi_ch_t
{
if constexpr (channelCount == DynamicChannelCount)
{
return m_channels;
}
else
{
return static_cast<pi_ch_t>(channelCount);
}
}

auto frames() const -> f_cnt_t { return m_frames; }

/**
* WARNING: This method assumes that internally there is a single
* contiguous buffer for all channels whose size is channels() * frames().
* Whether this is true depends on the implementation of the source buffer.
*/
auto sourceBuffer() const -> SplitSampleType<SampleT>*
{
assert(m_data != nullptr);
return m_data[0];
}

auto data() const -> SplitSampleType<SampleT>* const* { return m_data; }

private:
SplitSampleType<SampleT>* const* m_data = nullptr;
pi_ch_t m_channels = 0;
f_cnt_t m_frames = 0;
};


//! Converts between sample types
template<typename Out, typename In>
inline auto convertSample(const In sample) -> Out
{
if constexpr (std::is_floating_point_v<In> && std::is_floating_point_v<Out>)
{
return static_cast<Out>(sample);
}
else
{
static_assert(always_false_v<In, Out>, "only implemented for floating point samples");
}
}


} // namespace lmms

#endif // LMMS_AUDIO_DATA_H
Loading
Loading