Skip to content

Commit 71116a5

Browse files
committed
fix build against modern OBS
1 parent a1dd993 commit 71116a5

7 files changed

Lines changed: 202 additions & 63 deletions

File tree

CMakeLists.txt

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ include(GNUInstallDirs)
3232
if(UNIX)
3333
option(PACKAGED_INSTALL "Use folder structure for package managers and system-wide installs" OFF)
3434
option(MAKE_DEB "Package as .deb" OFF)
35+
option(CMAKE_POSITION_INDEPENDENT_CODE "Use -fPIC" ON)
3536
endif()
3637

3738
option(ENABLE_X86_SIMD "Enable x86 SIMD optimizations" ON)
@@ -113,9 +114,6 @@ if(BUILTIN_FFTW)
113114
#option(ENABLE_AVX "Compile with AVX instruction set support" ON) # i think this results in global VEX when building with CMake
114115
endif()
115116
add_subdirectory("deps/fftw-3.3.10" EXCLUDE_FROM_ALL)
116-
if(NOT MSVC AND NOT BUILD_SHARED_LIBS)
117-
target_compile_options(fftw3f PRIVATE "-fPIC") # GCC complains
118-
endif()
119117
set(FFTW_LIBRARIES fftw3f)
120118
set(FFTW_INCLUDE_DIRS "deps/fftw-3.3.10/api")
121119
else()
@@ -140,6 +138,7 @@ set(PLUGIN_SOURCES
140138
"src/source.cpp"
141139
"src/source_generic.cpp"
142140
"src/aligned_buffer.hpp"
141+
"src/circular_buffer.hpp"
143142
"src/math_funcs.hpp"
144143
"src/filter.hpp"
145144
"src/settings.hpp"
@@ -166,9 +165,6 @@ if(ENABLE_X86_SIMD)
166165
endif()
167166

168167
add_subdirectory(deps/cpu_features EXCLUDE_FROM_ALL)
169-
if(NOT MSVC AND NOT BUILD_SHARED_LIBS) # Clang complains
170-
target_compile_options(cpu_features PRIVATE "-fPIC")
171-
endif()
172168
endif()
173169

174170
if(MAKE_BUNDLE)

src/circular_buffer.hpp

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
#pragma once
2+
3+
#include <algorithm>
4+
#include <cstddef>
5+
#include <cstring>
6+
#include <vector>
7+
#include <cassert>
8+
9+
// Replacement for OBS's circlebuf API
10+
class CircularBuffer
11+
{
12+
public:
13+
CircularBuffer() { m_data.resize(4096); }
14+
~CircularBuffer() = default;
15+
CircularBuffer(const CircularBuffer&) = delete;
16+
CircularBuffer& operator=(const CircularBuffer&) = delete;
17+
18+
void reset() noexcept
19+
{
20+
m_pos = 0;
21+
m_used = 0;
22+
}
23+
24+
size_t size() const noexcept
25+
{
26+
return m_used;
27+
}
28+
29+
void reserve(size_t size)
30+
{
31+
if(m_data.size() >= size)
32+
return;
33+
34+
compact();
35+
36+
// NOTE: forcing a power of 2 would enable fast modulo,
37+
// but for now let's focus on conserving memory.
38+
constexpr auto align_mask = ~(size_t)1023;
39+
auto new_size = (size + 1024) & align_mask;
40+
m_data.resize(new_size);
41+
}
42+
43+
void push_back(const void *src, size_t size)
44+
{
45+
assert(m_pos < m_data.size());
46+
if(size == 0) [[unlikely]]
47+
return;
48+
49+
reserve(m_used + size);
50+
51+
auto write_pos = (m_pos + m_used) % m_data.size();
52+
auto avail = m_data.size() - write_pos;
53+
54+
if(avail >= size)
55+
{
56+
std::memcpy(m_data.data() + write_pos, src, size);
57+
}
58+
else
59+
{
60+
std::memcpy(m_data.data() + write_pos, src, avail);
61+
std::memcpy(m_data.data(), (const uint8_t*)src + avail, size - avail);
62+
}
63+
64+
m_used += size;
65+
}
66+
67+
void push_back_zero(size_t size)
68+
{
69+
assert(m_pos < m_data.size());
70+
if(size == 0) [[unlikely]]
71+
return;
72+
73+
reserve(m_used + size);
74+
75+
auto write_pos = (m_pos + m_used) % m_data.size();
76+
auto avail = m_data.size() - write_pos;
77+
78+
if(avail >= size)
79+
{
80+
std::memset(m_data.data() + write_pos, 0, size);
81+
}
82+
else
83+
{
84+
std::memset(m_data.data() + write_pos, 0, avail);
85+
std::memset(m_data.data(), 0, size - avail);
86+
}
87+
88+
m_used += size;
89+
}
90+
91+
void pop_front(void *dest, size_t size)
92+
{
93+
assert(m_data.size() > 0);
94+
assert(m_pos < m_data.size());
95+
if(size == 0) [[unlikely]]
96+
return;
97+
size = std::min(size, m_used);
98+
99+
auto avail = m_data.size() - m_pos;
100+
101+
if(dest != nullptr)
102+
{
103+
if(avail >= size)
104+
{
105+
std::memcpy(dest, &m_data[m_pos], size);
106+
}
107+
else
108+
{
109+
std::memcpy(dest, &m_data[m_pos], avail);
110+
std::memcpy((uint8_t*)dest + avail, m_data.data(), size - avail);
111+
}
112+
}
113+
114+
m_pos = (m_pos + size) % m_data.size();
115+
m_used -= size;
116+
}
117+
118+
void peek_front(void *dest, size_t size)
119+
{
120+
assert(m_data.size() > 0);
121+
assert(m_pos < m_data.size());
122+
if(size == 0) [[unlikely]]
123+
return;
124+
if(dest == nullptr) [[unlikely]]
125+
return;
126+
size = std::min(size, m_used);
127+
128+
auto avail = m_data.size() - m_pos;
129+
130+
if(avail >= size)
131+
{
132+
std::memcpy(dest, &m_data[m_pos], size);
133+
}
134+
else
135+
{
136+
std::memcpy(dest, &m_data[m_pos], avail);
137+
std::memcpy((uint8_t*)dest + avail, m_data.data(), size - avail);
138+
}
139+
}
140+
141+
private:
142+
std::vector<uint8_t> m_data;
143+
size_t m_pos = 0;
144+
size_t m_used = 0;
145+
146+
void compact()
147+
{
148+
if((m_pos + m_used) > m_data.size())
149+
{
150+
auto first = m_data.begin();
151+
auto last = m_data.end();
152+
std::rotate(first, first + m_pos, last);
153+
m_pos = 0;
154+
}
155+
}
156+
};

src/source.cpp

Lines changed: 16 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -741,14 +741,8 @@ void WAVSource::release_audio_capture()
741741

742742
// reset circular buffers
743743
for(auto& i : m_capturebufs)
744-
{
745-
i.end_pos = 0;
746-
i.start_pos = 0;
747-
i.size = 0;
748-
}
749-
m_rms_sync_buf.end_pos = 0;
750-
m_rms_sync_buf.start_pos = 0;
751-
m_rms_sync_buf.size = 0;
744+
i.reset();
745+
m_rms_sync_buf.reset();
752746

753747
m_capture_ts = 0;
754748
m_audio_ts = 0;
@@ -818,21 +812,21 @@ bool WAVSource::sync_rms_buffer()
818812
const int64_t dtaudio = get_audio_sync(m_tick_ts);
819813
const size_t dtsize = (dtaudio > 0) ? size_t(ns_to_audio_frames(m_audio_info.samples_per_sec, (uint64_t)dtaudio)) * sizeof(float) : 0;
820814

821-
if(m_rms_sync_buf.size <= dtsize)
815+
if(m_rms_sync_buf.size() <= dtsize)
822816
return false;
823817

824-
while(m_rms_sync_buf.size > dtsize)
818+
while(m_rms_sync_buf.size() > dtsize)
825819
{
826-
auto consume = m_rms_sync_buf.size - dtsize;
820+
auto consume = m_rms_sync_buf.size() - dtsize;
827821
auto max = (m_input_rms_size - m_input_rms_pos) * sizeof(float);
828822
if(consume >= max)
829823
{
830-
circlebuf_pop_front(&m_rms_sync_buf, &m_input_rms_buf[m_input_rms_pos], max);
824+
m_rms_sync_buf.pop_front(&m_input_rms_buf[m_input_rms_pos], max);
831825
m_input_rms_pos = 0;
832826
}
833827
else
834828
{
835-
circlebuf_pop_front(&m_rms_sync_buf, &m_input_rms_buf[m_input_rms_pos], consume);
829+
m_rms_sync_buf.pop_front(&m_input_rms_buf[m_input_rms_pos], consume);
836830
m_input_rms_pos += consume / sizeof(float);
837831
}
838832
}
@@ -941,9 +935,6 @@ void WAVSource::init_steps()
941935
WAVSource::WAVSource(obs_source_t *source)
942936
{
943937
m_source = source;
944-
for(auto& i : m_capturebufs)
945-
circlebuf_init(&i);
946-
circlebuf_init(&m_rms_sync_buf);
947938

948939
obs_enter_graphics();
949940

@@ -964,10 +955,6 @@ WAVSource::~WAVSource()
964955

965956
release_audio_capture();
966957
free_bufs();
967-
968-
for(auto& i : m_capturebufs)
969-
circlebuf_free(&i);
970-
circlebuf_free(&m_rms_sync_buf);
971958
}
972959

973960
unsigned int WAVSource::width()
@@ -1015,7 +1002,7 @@ void WAVSource::create_vbuf() {
10151002
num_verts += m_cap_tris * ((m_channel_spacing > 0) ? 12 : 6) * m_num_bars; // 2 caps per bar (middle omitted when 0 spacing)
10161003
}
10171004

1018-
constexpr auto signbit = (size_t)1 << ((sizeof(num_verts) * 8) - 1);
1005+
[[maybe_unused]] constexpr auto signbit = (size_t)1 << ((sizeof(num_verts) * 8) - 1);
10191006
assert(num_verts > 0);
10201007
assert((num_verts & signbit) == 0); // if MSB is set something has gone very wrong
10211008
assert((num_verts * sizeof(vec3)) < (1u << 30)); // abnormally large allocation
@@ -1257,7 +1244,7 @@ void WAVSource::update(obs_data_t *settings)
12571244
{
12581245
// fill input buffers with silent audio to avoid startup lag e.g. when changing settings
12591246
for(auto i = 0u; i < m_capture_channels; ++i)
1260-
circlebuf_push_back_zero(&m_capturebufs[i], m_fft_size * sizeof(float));
1247+
m_capturebufs[i].push_back_zero(m_fft_size * sizeof(float));
12611248
}
12621249

12631250
// precomupte interpolated indices
@@ -1873,14 +1860,14 @@ void WAVSource::capture_audio([[maybe_unused]] obs_source_t *source, const audio
18731860
}
18741861
m_rms_temp_buf[i] = val * val;
18751862
}
1876-
circlebuf_push_back(&m_rms_sync_buf, m_rms_temp_buf.get(), count * sizeof(float));
1863+
m_rms_sync_buf.push_back(m_rms_temp_buf.get(), count * sizeof(float));
18771864
frames -= count;
18781865
}
18791866

18801867
const size_t max_rms_size = (dtsamples * sizeof(float)) + (m_input_rms_size * sizeof(float));
1881-
auto total = m_rms_sync_buf.size;
1868+
auto total = m_rms_sync_buf.size();
18821869
if(total > max_rms_size)
1883-
circlebuf_pop_front(&m_rms_sync_buf, nullptr, total - max_rms_size);
1870+
m_rms_sync_buf.pop_front(nullptr, total - max_rms_size);
18841871
}
18851872

18861873
auto sz = size_t(audio->frames * sizeof(float));
@@ -1889,14 +1876,14 @@ void WAVSource::capture_audio([[maybe_unused]] obs_source_t *source, const audio
18891876
auto j = i - m_channel_base;
18901877
assert((j == 0) || (j == 1));
18911878
if((muted && !m_ignore_mute) || (audio->data[i] == nullptr))
1892-
circlebuf_push_back_zero(&m_capturebufs[j], sz);
1879+
m_capturebufs[j].push_back_zero(sz);
18931880
else
1894-
circlebuf_push_back(&m_capturebufs[j], audio->data[i], sz);
1881+
m_capturebufs[j].push_back(audio->data[i], sz);
18951882

18961883
const size_t max_size = (dtsamples * sizeof(float)) + bufsz;
1897-
auto total = m_capturebufs[j].size;
1884+
auto total = m_capturebufs[j].size();
18981885
if(total > max_size)
1899-
circlebuf_pop_front(&m_capturebufs[j], nullptr, total - max_size);
1886+
m_capturebufs[j].pop_front(nullptr, total - max_size);
19001887
}
19011888
}
19021889

src/source.hpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,12 @@
1818
#pragma once
1919
#include <mutex>
2020
#include <obs-module.h>
21-
#include <util/circlebuf.h>
2221
#include <graphics/vec3.h>
2322
#include <graphics/vec4.h>
2423
#include <fftw3.h>
2524
#include "module.hpp"
2625
#include "aligned_buffer.hpp"
26+
#include "circular_buffer.hpp"
2727
#include "filter.hpp"
2828

2929
using AVXBufR = AlignedBuffer<float>;
@@ -107,7 +107,7 @@ class WAVSource
107107

108108
// audio capture
109109
obs_audio_info m_audio_info{};
110-
circlebuf m_capturebufs[2]{};
110+
CircularBuffer m_capturebufs[2];
111111
uint32_t m_capture_channels = 0; // audio input channels
112112
uint32_t m_output_channels = 0; // fft output channels (*not* display channels)
113113
bool m_output_bus_captured = false; // do we have an active audio output callback? (via audio_output_connect())
@@ -239,7 +239,7 @@ class WAVSource
239239
float m_input_rms = 0.0f;
240240
AVXBufR m_input_rms_buf;
241241
AVXBufR m_rms_temp_buf; // temp buffer, bit too large for stack
242-
circlebuf m_rms_sync_buf{}; // A/V syncronization buffer
242+
CircularBuffer m_rms_sync_buf; // A/V syncronization buffer
243243
size_t m_input_rms_size = 0;
244244
size_t m_input_rms_pos = 0;
245245

src/source_avx.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,10 @@ void WAVSourceAVX::tick_spectrum([[maybe_unused]] float seconds)
5555
auto silent_channels = 0u;
5656
for(auto channel = 0u; channel < m_capture_channels; ++channel)
5757
{
58-
if(m_capturebufs[channel].size >= dtsize)
58+
if(m_capturebufs[channel].size() >= dtsize)
5959
{
60-
circlebuf_pop_front(&m_capturebufs[channel], nullptr, m_capturebufs[channel].size - dtsize);
61-
circlebuf_peek_front(&m_capturebufs[channel], m_fft_input.get(), bufsz);
60+
m_capturebufs[channel].pop_front(nullptr, m_capturebufs[channel].size() - dtsize);
61+
m_capturebufs[channel].peek_front(m_fft_input.get(), bufsz);
6262
}
6363
else
6464
continue;
@@ -227,18 +227,18 @@ void WAVSourceAVX::tick_meter([[maybe_unused]] float seconds)
227227
// repurpose m_decibels as circular buffer for sample data
228228
for(auto channel = 0u; channel < m_capture_channels; ++channel)
229229
{
230-
while(m_capturebufs[channel].size > dtsize)
230+
while(m_capturebufs[channel].size() > dtsize)
231231
{
232-
auto consume = m_capturebufs[channel].size - dtsize;
232+
auto consume = m_capturebufs[channel].size() - dtsize;
233233
auto max = (m_fft_size - m_meter_pos[channel]) * sizeof(float);
234234
if(consume >= max)
235235
{
236-
circlebuf_pop_front(&m_capturebufs[channel], &m_decibels[channel][m_meter_pos[channel]], max);
236+
m_capturebufs[channel].pop_front(&m_decibels[channel][m_meter_pos[channel]], max);
237237
m_meter_pos[channel] = 0;
238238
}
239239
else
240240
{
241-
circlebuf_pop_front(&m_capturebufs[channel], &m_decibels[channel][m_meter_pos[channel]], consume);
241+
m_capturebufs[channel].pop_front(&m_decibels[channel][m_meter_pos[channel]], consume);
242242
m_meter_pos[channel] += consume / sizeof(float);
243243
}
244244
}

src/source_avx2.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,10 +53,10 @@ void WAVSourceAVX2::tick_spectrum([[maybe_unused]] float seconds)
5353
for(auto channel = 0u; channel < m_capture_channels; ++channel)
5454
{
5555
// get captured audio
56-
if(m_capturebufs[channel].size >= dtsize)
56+
if(m_capturebufs[channel].size() >= dtsize)
5757
{
58-
circlebuf_pop_front(&m_capturebufs[channel], nullptr, m_capturebufs[channel].size - dtsize);
59-
circlebuf_peek_front(&m_capturebufs[channel], m_fft_input.get(), bufsz);
58+
m_capturebufs[channel].pop_front(nullptr, m_capturebufs[channel].size() - dtsize);
59+
m_capturebufs[channel].peek_front(m_fft_input.get(), bufsz);
6060
}
6161
else
6262
continue;

0 commit comments

Comments
 (0)