2020 Dennis Braun <d_braun@kabelmail.de>
License: GPL-3+
+Files: debian/missing-sources/mcl-*
+Copyright:
+ 2021 Giovanni A. Zuliani | Monocasual
+License: GPL-3+
+
Files: src/deps/rtaudio/RtAudio.h
src/deps/rtaudio/RtAudio.cpp
Copyright:
--- /dev/null
+missing sources for giada
+=========================
+
+this directory contains sources that are missing from upstream's tarball.
+
+
+mcl-atomic-swapper
+==================
+
+is a tiny (1 source file) module released under the GPLv3+,
+maintained by giada upstream in a separate repository.
+
+mcl-audio-buffer
+================
+
+is a tiny (2 source files) module released under the GPLv3+,
+maintained by giada upstream in a separate repository.
+
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * Atomic Swapper
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2021 Giovanni A. Zuliani | Monocasual Laboratories
+ *
+ * This file is part of Atomic Swapper.
+ *
+ * Atomic Swapper 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 3 of the License, or (at your option) any later version.
+ *
+ * Atomic Swapper 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 Atomic Swapper. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+#ifndef MONOCASUAL_ATOMIC_SWAPPER_H
+#define MONOCASUAL_ATOMIC_SWAPPER_H
+
+#include <array>
+#include <atomic>
+
+namespace mcl
+{
+template <typename T>
+class AtomicSwapper
+{
+public:
+ class RtLock
+ {
+ friend AtomicSwapper;
+
+ public:
+ RtLock(AtomicSwapper& s)
+ : m_swapper(s)
+ {
+ m_swapper.rt_lock();
+ }
+
+ ~RtLock()
+ {
+ m_swapper.rt_unlock();
+ }
+
+ const T& get() const
+ {
+ return m_swapper.rt_get();
+ }
+
+ private:
+ AtomicSwapper& m_swapper;
+ };
+
+ AtomicSwapper()
+ {
+ static_assert(std::is_assignable_v<T, T>);
+ }
+
+ /* isLocked
+ Returns true if the busy bit is currently set, that is if the realtime
+ thread is reading its copy of data. */
+
+ bool isLocked() const
+ {
+ return m_bits.load() & BIT_BUSY;
+ }
+
+ /* get (1)
+ Returns local data for non-realtime thread. */
+
+ const T& get() const
+ {
+ return m_data[(m_bits.load() & BIT_INDEX) ^ 1];
+ }
+
+ /* get (2)
+ As above, non-const version. */
+
+ T& get()
+ {
+ return const_cast<T&>(static_cast<const AtomicSwapper&>(*this).get());
+ }
+
+ /* swap
+ Core function: swaps the realtime data with the non-realtime one. Waits for
+ the realtime thread until it has finished reading its own copy of data. Only
+ then the indexes are swapped atomically. */
+
+ void swap()
+ {
+ int bits = m_bits.load();
+
+ /* Wait for the realtime thread to finish, i.e. until the BUSY bit
+ becomes zero. Only then, swap indexes. This will let the realtime thread
+ to pick the updated data on its next cycle. */
+ int desired;
+ do
+ {
+ bits = bits & ~BIT_BUSY; // Expected: current value without busy bit set
+ desired = (bits ^ BIT_INDEX) & BIT_INDEX; // Desired: flipped (xor) index
+ } while (!m_bits.compare_exchange_weak(bits, desired));
+
+ bits = desired;
+
+ /* After the swap above, m_data[(bits & BIT_INDEX) ^ 1] has become the
+ non-realtime slot and it points to the data previously read by the
+ realtime thread. That data is old, so update it: overwrite it with the
+ realtime data in the realtime slot (m_data[bits & BIT_INDEX]) that is
+ currently being read by the realtime thread. */
+ m_data[(bits & BIT_INDEX) ^ 1] = m_data[bits & BIT_INDEX];
+ }
+
+private:
+ static constexpr int BIT_INDEX = (1 << 0); // 0001
+ static constexpr int BIT_BUSY = (1 << 1); // 0010
+
+ /* [realtime] lock
+ Marks the data as busy. Used when the realtime thread starts reading its own
+ copy of data. Can't call this directly (it's private), use the scoped lock
+ RtLock class above. */
+
+ void rt_lock()
+ {
+ /* Set the busy bit and also get the current index. */
+ m_index = m_bits.fetch_or(BIT_BUSY) & BIT_INDEX;
+ }
+
+ /* [realtime] unlock
+ Marks the data as free. Used when the realtime thread is done with reading
+ its own copy of data. Can't call this directly (it's private), use the
+ scoped lock RtLock class above. */
+
+ void rt_unlock()
+ {
+ m_bits.store(m_index & BIT_INDEX);
+ }
+
+ /* [realtime] get
+ Get data currently being ready by the realtime thread. Can't call this
+ directly (it's private), use the scoped lock RtLock class above.*/
+
+ const T& rt_get() const
+ {
+ return m_data[m_bits.load() & BIT_INDEX];
+ }
+
+ std::array<T, 2> m_data;
+ std::atomic<int> m_bits{0};
+ int m_index{0};
+};
+} // namespace mcl
+
+#endif
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * AudioBuffer
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2021 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of AudioBuffer.
+ *
+ * AudioBuffer 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 3 of the License, or (at your option) any later
+ * version.
+ *
+ * AudioBuffer 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
+ * AudioBuffer. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+#include "audioBuffer.hpp"
+#include <algorithm>
+#include <cassert>
+
+namespace mcl
+{
+AudioBuffer::AudioBuffer()
+: m_data(nullptr)
+, m_size(0)
+, m_channels(0)
+, m_viewing(false)
+{
+}
+
+/* -------------------------------------------------------------------------- */
+
+AudioBuffer::AudioBuffer(int size, int channels)
+: AudioBuffer()
+{
+ alloc(size, channels);
+}
+
+/* -------------------------------------------------------------------------- */
+
+AudioBuffer::AudioBuffer(float* data, int size, int channels)
+: m_data(data)
+, m_size(size)
+, m_channels(channels)
+, m_viewing(true)
+{
+ assert(channels <= NUM_CHANS);
+}
+
+/* -------------------------------------------------------------------------- */
+
+AudioBuffer::AudioBuffer(const AudioBuffer& o)
+{
+ copy(o);
+}
+
+/* -------------------------------------------------------------------------- */
+
+AudioBuffer::AudioBuffer(AudioBuffer&& o)
+{
+ move(std::move(o));
+}
+
+/* -------------------------------------------------------------------------- */
+
+AudioBuffer::~AudioBuffer()
+{
+ if (!m_viewing)
+ free();
+}
+
+/* -------------------------------------------------------------------------- */
+
+AudioBuffer& AudioBuffer::operator=(const AudioBuffer& o)
+{
+ if (this == &o)
+ return *this;
+ copy(o);
+ return *this;
+}
+
+/* -------------------------------------------------------------------------- */
+
+AudioBuffer& AudioBuffer::operator=(AudioBuffer&& o)
+{
+ if (this == &o)
+ return *this;
+ move(std::move(o));
+ return *this;
+}
+
+/* -------------------------------------------------------------------------- */
+
+float* AudioBuffer::operator[](int offset) const
+{
+ assert(m_data != nullptr);
+ assert(offset < m_size);
+ return m_data + (offset * m_channels);
+}
+
+/* -------------------------------------------------------------------------- */
+
+void AudioBuffer::clear(int a, int b)
+{
+ if (m_data == nullptr)
+ return;
+ if (b == -1)
+ b = m_size;
+ std::fill_n(m_data + (a * m_channels), (b - a) * m_channels, 0.0);
+}
+
+/* -------------------------------------------------------------------------- */
+
+int AudioBuffer::countFrames() const { return m_size; }
+int AudioBuffer::countSamples() const { return m_size * m_channels; }
+int AudioBuffer::countChannels() const { return m_channels; }
+bool AudioBuffer::isAllocd() const { return m_data != nullptr; }
+
+/* -------------------------------------------------------------------------- */
+
+float AudioBuffer::getPeak(int channel) const
+{
+ assert(channel < m_channels);
+
+ float peak = 0.0f;
+ for (int i = 0; i < countFrames(); i++)
+ peak = std::max(peak, (*this)[i][channel]);
+ return peak;
+}
+
+/* -------------------------------------------------------------------------- */
+
+void AudioBuffer::alloc(int size, int channels)
+{
+ assert(channels <= NUM_CHANS);
+
+ free();
+ m_size = size;
+ m_channels = channels;
+ m_data = new float[m_size * m_channels];
+ clear();
+}
+
+/* -------------------------------------------------------------------------- */
+
+void AudioBuffer::free()
+{
+ if (m_data == nullptr)
+ return;
+ delete[] m_data;
+ m_data = nullptr;
+ m_size = 0;
+ m_channels = 0;
+ m_viewing = false;
+}
+
+/* -------------------------------------------------------------------------- */
+
+void AudioBuffer::sum(const AudioBuffer& b, int framesToCopy, int srcOffset,
+ int destOffset, float gain, Pan pan)
+{
+ copyData<Operation::SUM>(b, framesToCopy, srcOffset, destOffset, gain, pan);
+}
+
+void AudioBuffer::set(const AudioBuffer& b, int framesToCopy, int srcOffset,
+ int destOffset, float gain, Pan pan)
+{
+ copyData<Operation::SET>(b, framesToCopy, srcOffset, destOffset, gain, pan);
+}
+
+void AudioBuffer::sum(const AudioBuffer& b, float gain, Pan pan)
+{
+ copyData<Operation::SUM>(b, -1, 0, 0, gain, pan);
+}
+
+void AudioBuffer::set(const AudioBuffer& b, float gain, Pan pan)
+{
+ copyData<Operation::SET>(b, -1, 0, 0, gain, pan);
+}
+
+/* -------------------------------------------------------------------------- */
+
+template <AudioBuffer::Operation O>
+void AudioBuffer::copyData(const AudioBuffer& b, int framesToCopy,
+ int srcOffset, int destOffset, float gain, Pan pan)
+{
+ const int srcChannels = b.countChannels();
+ const int destChannels = countChannels();
+ const bool sameChannels = srcChannels == destChannels;
+
+ assert(m_data != nullptr);
+ assert(destOffset >= 0 && destOffset < m_size);
+ assert(srcChannels <= destChannels);
+
+ /* Make sure the amount of frames to copy lies within the current buffer
+ size. */
+
+ framesToCopy = framesToCopy == -1 ? b.countFrames() : framesToCopy;
+ framesToCopy = std::min(framesToCopy, m_size - destOffset);
+
+ /* Case 1) source has less channels than this one: brutally spread source's
+ channel 0 over this one (TODO - maybe mixdown source channels first?)
+ Case 2) source has same amount of channels: copy them 1:1. */
+
+ for (int destF = 0, srcF = srcOffset; destF < framesToCopy && destF < b.countFrames(); destF++, srcF++)
+ {
+ for (int ch = 0; ch < destChannels; ch++)
+ {
+ if constexpr (O == Operation::SUM)
+ sum(destF + destOffset, ch, b[srcF][sameChannels ? ch : 0] * gain * pan[ch]);
+ else
+ set(destF + destOffset, ch, b[srcF][sameChannels ? ch : 0] * gain * pan[ch]);
+ }
+ }
+}
+
+/* -------------------------------------------------------------------------- */
+
+void AudioBuffer::applyGain(float g)
+{
+ for (int i = 0; i < countSamples(); i++)
+ m_data[i] *= g;
+}
+
+/* -------------------------------------------------------------------------- */
+
+void AudioBuffer::sum(int f, int channel, float val) { (*this)[f][channel] += val; }
+void AudioBuffer::set(int f, int channel, float val) { (*this)[f][channel] = val; }
+
+/* -------------------------------------------------------------------------- */
+
+void AudioBuffer::move(AudioBuffer&& o)
+{
+ assert(o.countChannels() <= NUM_CHANS);
+
+ m_data = o.m_data;
+ m_size = o.m_size;
+ m_channels = o.m_channels;
+ m_viewing = o.m_viewing;
+
+ o.m_data = nullptr;
+ o.m_size = 0;
+ o.m_channels = 0;
+ o.m_viewing = false;
+}
+
+/* -------------------------------------------------------------------------- */
+
+void AudioBuffer::copy(const AudioBuffer& o)
+{
+ m_data = new float[o.m_size * o.m_channels];
+ m_size = o.m_size;
+ m_channels = o.m_channels;
+ m_viewing = o.m_viewing;
+
+ std::copy(o.m_data, o.m_data + (o.m_size * o.m_channels), m_data);
+}
+
+/* -------------------------------------------------------------------------- */
+
+template void AudioBuffer::copyData<AudioBuffer::Operation::SUM>(const AudioBuffer&, int, int, int, float, Pan);
+template void AudioBuffer::copyData<AudioBuffer::Operation::SET>(const AudioBuffer&, int, int, int, float, Pan);
+} // namespace mcl
\ No newline at end of file
--- /dev/null
+/* -----------------------------------------------------------------------------
+ *
+ * AudioBuffer
+ *
+ * -----------------------------------------------------------------------------
+ *
+ * Copyright (C) 2021 Giovanni A. Zuliani | Monocasual
+ *
+ * This file is part of AudioBuffer.
+ *
+ * AudioBuffer 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 3 of the License, or (at your option) any later
+ * version.
+ *
+ * AudioBuffer 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
+ * AudioBuffer. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * -------------------------------------------------------------------------- */
+
+#ifndef MONOCASUAL_AUDIO_BUFFER_H
+#define MONOCASUAL_AUDIO_BUFFER_H
+
+#include <array>
+
+namespace mcl
+{
+/* AudioBuffer
+A class that holds a buffer filled with audio data. NOTE: currently it only
+supports 2 channels (stereo). Give it a mono stream and it will convert it to
+stereo. Give it a multichannel stream and it will throw an assertion. */
+
+class AudioBuffer
+{
+public:
+ static constexpr int NUM_CHANS = 2;
+
+ using Pan = std::array<float, NUM_CHANS>;
+
+ /* AudioBuffer (1)
+ Creates an empty (and invalid) audio buffer. */
+
+ AudioBuffer();
+
+ /* AudioBuffer (2)
+ Creates an audio buffer and allocates memory for size * channels frames. */
+
+ AudioBuffer(int size, int channels);
+
+ /* AudioBuffer (3)
+ Creates an audio buffer out of a raw pointer. AudioBuffer created this way
+ is instructed not to free the owned data on destruction. */
+
+ AudioBuffer(float* data, int size, int channels);
+
+ /* AudioBuffer(const AudioBuffer&)
+ Copy constructor. */
+
+ AudioBuffer(const AudioBuffer& o);
+
+ /* AudioBuffer(AudioBuffer&&)
+ Move constructor. */
+
+ AudioBuffer(AudioBuffer&& o);
+
+ /* ~AudioBuffer
+ Destructor. */
+
+ ~AudioBuffer();
+
+ /* operator = (const AudioBuffer& o)
+ Copy assignment operator. */
+
+ AudioBuffer& operator=(const AudioBuffer& o);
+
+ /* operator = (AudioBuffer&& o)
+ Move assignment operator. */
+
+ AudioBuffer& operator=(AudioBuffer&& o);
+
+ /* operator []
+ Given a frame 'offset', returns a pointer to it. This is useful for digging
+ inside a frame, i.e. parsing each channel. How to use it:
+
+ for (int k=0; k<buffer->countFrames(), k++)
+ for (int i=0; i<buffer->countChannels(); i++)
+ ... buffer[k][i] ...
+
+ Also note that buffer[0] will give you a pointer to the whole internal data
+ array. */
+
+ float* operator[](int offset) const;
+
+ int countFrames() const;
+ int countSamples() const;
+ int countChannels() const;
+ bool isAllocd() const;
+
+ /* getPeak
+ Returns the highest value from the specified channel. */
+
+ float getPeak(int channel) const;
+
+ void alloc(int size, int channels);
+ void free();
+
+ /* sum, set (1)
+ Merges (sum) or copies (set) 'framesToCopy' frames of buffer 'b' onto this
+ one. If 'framesToCopy' is -1 the whole buffer will be copied. If 'b' has
+ less channels than this one, they will be spread over the current ones.
+ Buffer 'b' MUST NOT contain more channels than this one. */
+
+ void sum(const AudioBuffer& b, int framesToCopy = -1, int srcOffset = 0,
+ int destOffset = 0, float gain = 1.0f, Pan pan = {1.0f, 1.0f});
+ void set(const AudioBuffer& b, int framesToCopy = -1, int srcOffset = 0,
+ int destOffset = 0, float gain = 1.0f, Pan pan = {1.0f, 1.0f});
+
+ /* sum, set (2)
+ Same as sum, set (1) without boundaries or offsets: it just copies as much
+ as possibile. */
+
+ void sum(const AudioBuffer& b, float gain = 1.0f, Pan pan = {1.0f, 1.0f});
+ void set(const AudioBuffer& b, float gain = 1.0f, Pan pan = {1.0f, 1.0f});
+
+ /* clear
+ Clears the internal data by setting all bytes to 0.0f. Optional parameters
+ 'a' and 'b' set the range. */
+
+ void clear(int a = 0, int b = -1);
+
+ void applyGain(float g);
+
+private:
+ enum class Operation
+ {
+ SUM,
+ SET
+ };
+
+ template <Operation O = Operation::SET>
+ void copyData(const AudioBuffer& b, int framesToCopy = -1,
+ int srcOffset = 0, int destOffset = 0, float gain = 1.0f,
+ Pan pan = {1.0f, 1.0f});
+
+ void move(AudioBuffer&& o);
+ void copy(const AudioBuffer& o);
+ void sum(int f, int channel, float val);
+ void set(int f, int channel, float val);
+
+ float* m_data;
+ int m_size;
+ int m_channels;
+ bool m_viewing;
+};
+} // namespace mcl
+
+#endif
\ No newline at end of file