From ae0a7107614b005467524d4e5ec9e61db74928c2 Mon Sep 17 00:00:00 2001 From: =?utf8?q?IOhannes=20m=20zm=C3=B6lnig=20=28Debian/GNU=29?= Date: Fri, 17 Dec 2021 09:57:56 +0100 Subject: [PATCH] Add missing upstream sources --- debian/copyright | 5 + debian/missing-sources/README.md | 18 ++ .../mcl-atomic-swapper/atomic-swapper.hpp | 163 +++++++++++ .../mcl-audio-buffer/audioBuffer.cpp | 273 ++++++++++++++++++ .../mcl-audio-buffer/audioBuffer.hpp | 163 +++++++++++ 5 files changed, 622 insertions(+) create mode 100644 debian/missing-sources/README.md create mode 100644 debian/missing-sources/mcl-atomic-swapper/atomic-swapper.hpp create mode 100644 debian/missing-sources/mcl-audio-buffer/audioBuffer.cpp create mode 100644 debian/missing-sources/mcl-audio-buffer/audioBuffer.hpp diff --git a/debian/copyright b/debian/copyright index eede0c2..f9f6dee 100644 --- a/debian/copyright +++ b/debian/copyright @@ -19,6 +19,11 @@ Copyright: 2020 Dennis Braun 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: diff --git a/debian/missing-sources/README.md b/debian/missing-sources/README.md new file mode 100644 index 0000000..cc45e02 --- /dev/null +++ b/debian/missing-sources/README.md @@ -0,0 +1,18 @@ +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. + diff --git a/debian/missing-sources/mcl-atomic-swapper/atomic-swapper.hpp b/debian/missing-sources/mcl-atomic-swapper/atomic-swapper.hpp new file mode 100644 index 0000000..e3ca0d5 --- /dev/null +++ b/debian/missing-sources/mcl-atomic-swapper/atomic-swapper.hpp @@ -0,0 +1,163 @@ +/* ----------------------------------------------------------------------------- + * + * 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 + * . + * + * -------------------------------------------------------------------------- */ + +#ifndef MONOCASUAL_ATOMIC_SWAPPER_H +#define MONOCASUAL_ATOMIC_SWAPPER_H + +#include +#include + +namespace mcl +{ +template +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); + } + + /* 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(static_cast(*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 m_data; + std::atomic m_bits{0}; + int m_index{0}; +}; +} // namespace mcl + +#endif diff --git a/debian/missing-sources/mcl-audio-buffer/audioBuffer.cpp b/debian/missing-sources/mcl-audio-buffer/audioBuffer.cpp new file mode 100644 index 0000000..84a7df8 --- /dev/null +++ b/debian/missing-sources/mcl-audio-buffer/audioBuffer.cpp @@ -0,0 +1,273 @@ +/* ----------------------------------------------------------------------------- + * + * 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 + * . + * + * -------------------------------------------------------------------------- */ + +#include "audioBuffer.hpp" +#include +#include + +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(b, framesToCopy, srcOffset, destOffset, gain, pan); +} + +void AudioBuffer::set(const AudioBuffer& b, int framesToCopy, int srcOffset, + int destOffset, float gain, Pan pan) +{ + copyData(b, framesToCopy, srcOffset, destOffset, gain, pan); +} + +void AudioBuffer::sum(const AudioBuffer& b, float gain, Pan pan) +{ + copyData(b, -1, 0, 0, gain, pan); +} + +void AudioBuffer::set(const AudioBuffer& b, float gain, Pan pan) +{ + copyData(b, -1, 0, 0, gain, pan); +} + +/* -------------------------------------------------------------------------- */ + +template +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(const AudioBuffer&, int, int, int, float, Pan); +template void AudioBuffer::copyData(const AudioBuffer&, int, int, int, float, Pan); +} // namespace mcl \ No newline at end of file diff --git a/debian/missing-sources/mcl-audio-buffer/audioBuffer.hpp b/debian/missing-sources/mcl-audio-buffer/audioBuffer.hpp new file mode 100644 index 0000000..9b3107f --- /dev/null +++ b/debian/missing-sources/mcl-audio-buffer/audioBuffer.hpp @@ -0,0 +1,163 @@ +/* ----------------------------------------------------------------------------- + * + * 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 + * . + * + * -------------------------------------------------------------------------- */ + +#ifndef MONOCASUAL_AUDIO_BUFFER_H +#define MONOCASUAL_AUDIO_BUFFER_H + +#include + +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; + + /* 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; kcountFrames(), k++) + for (int i=0; icountChannels(); 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 + 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 -- 2.30.2