Skip to content

Commit ac7f488

Browse files
committed
Merge branch 'multi-spectral-processor' into devel
* Implemented MultiSpectralProcessor class for multi-channel spectral processing.
2 parents 0ba454e + 35b102c commit ac7f488

File tree

5 files changed

+697
-14
lines changed

5 files changed

+697
-14
lines changed

CHANGELOG

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
*******************************************************************************
44

55
=== 1.0.33 ===
6+
* Implemented MultiSpectralProcessor class for multi-channel spectral processing.
67
* Spectral Processor now allows to analyze input signal without processing.
78
* Fixed noise envelope generation.
89
* Optimized noise envelope generation algorithm by using LSP DSP library.

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ Set of modules provided:
6262
* Impulse response taker
6363
* Latency detector
6464
* Meter history
65+
* Multi-channel spectral processor
6566
* Meter history with scaling option
6667
* Oscillator
6768
* Oversampler
Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
1+
/*
2+
* Copyright (C) 2025 Linux Studio Plugins Project <https://lsp-plug.in/>
3+
* (C) 2025 Vladimir Sadovnikov <[email protected]>
4+
*
5+
* This file is part of lsp-dsp-units
6+
* Created on: 13 нояб. 2025 г.
7+
*
8+
* lsp-dsp-units is free software: you can redistribute it and/or modify
9+
* it under the terms of the GNU Lesser General Public License as published by
10+
* the Free Software Foundation, either version 3 of the License, or
11+
* any later version.
12+
*
13+
* lsp-dsp-units is distributed in the hope that it will be useful,
14+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+
* GNU Lesser General Public License for more details.
17+
*
18+
* You should have received a copy of the GNU Lesser General Public License
19+
* along with lsp-dsp-units. If not, see <https://www.gnu.org/licenses/>.
20+
*/
21+
22+
#ifndef LSP_PLUG_IN_DSP_UNITS_UTIL_MULTISPECTRALPROCESSOR_H_
23+
#define LSP_PLUG_IN_DSP_UNITS_UTIL_MULTISPECTRALPROCESSOR_H_
24+
25+
#include <lsp-plug.in/dsp-units/version.h>
26+
27+
#include <lsp-plug.in/common/status.h>
28+
#include <lsp-plug.in/dsp-units/iface/IStateDumper.h>
29+
30+
namespace lsp
31+
{
32+
namespace dspu
33+
{
34+
/**
35+
* Multi-Spectral processor callback function
36+
* @param object the object that handles callback
37+
* @param subject the subject that is used to handle callback
38+
* @param spectrum spectral data for processing (packed complex numbers)
39+
* @param rank the overall rank of the FFT transform (log2(size))
40+
*/
41+
typedef void (* multi_spectral_processor_func_t)(void *object, void *subject, float * const * spectrum, size_t rank);
42+
43+
/**
44+
* Multi-Spectral processor class, performs multi-channel spectral transform of the input signal
45+
* and launches callback function to process the signal spectrum
46+
*/
47+
class LSP_DSP_UNITS_PUBLIC MultiSpectralProcessor
48+
{
49+
protected:
50+
typedef struct channel_t
51+
{
52+
const float *pIn; // Input data pointer
53+
float *pOut; // Output data pointer
54+
float *pInBuf; // Input buffer
55+
float *pOutBuf; // Output buffer
56+
float *pFftBuf; // FFT buffer
57+
} channel_t;
58+
59+
protected:
60+
void clear_buffers();
61+
62+
protected:
63+
uint32_t nChannels; // Number of channels
64+
uint32_t nRank; // Current FFT rank
65+
uint32_t nMaxRank; // Maximum FFT rank
66+
uint32_t nOffset; // Read/Write offset
67+
channel_t *vChannels; // Channels
68+
float **vFftBuf; // FFT transform buffers
69+
float *pWnd; // Window function
70+
float fPhase; // Phase
71+
bool bUpdate; // Update flag
72+
73+
// Bindings
74+
multi_spectral_processor_func_t pFunc; // Function
75+
void *pObject; // Object to operate
76+
void *pSubject; // Subject to operate
77+
78+
// Misc
79+
uint8_t *pData; // Data buffer
80+
81+
public:
82+
explicit MultiSpectralProcessor();
83+
MultiSpectralProcessor(const MultiSpectralProcessor &) = delete;
84+
MultiSpectralProcessor(MultiSpectralProcessor &&) = delete;
85+
~MultiSpectralProcessor();
86+
87+
MultiSpectralProcessor & operator = (const MultiSpectralProcessor &) = delete;
88+
MultiSpectralProcessor & operator = (MultiSpectralProcessor &&) = delete;
89+
90+
/**
91+
* Construct object
92+
*/
93+
void construct();
94+
95+
/**
96+
* Initialize spectral processor
97+
* @param channels number of channels
98+
* @param max_rank maximum FFT rank
99+
* @return status of operation
100+
*/
101+
bool init(size_t channels, size_t max_rank);
102+
103+
/**
104+
* Destroy spectral processor
105+
*/
106+
void destroy();
107+
108+
public:
109+
/**
110+
* Bind spectral processor to the handler
111+
* @param func function to call
112+
* @param object the target object to pass to the function
113+
* @param subject the target subject to pass to the function
114+
*/
115+
void bind_handler(multi_spectral_processor_func_t func, void *object, void *subject);
116+
117+
/**
118+
* Unbind spectral processor
119+
*/
120+
void unbind_handler();
121+
122+
/**
123+
* Bind buffers to the channel.
124+
* @param index index of the channel
125+
* @param out output buffer. If output buffer is not specified, back reverse FFT is not performed
126+
* @param in input buffer. If input buffer is not specified, processing of the channel is disabled
127+
* @return status of operation
128+
*/
129+
status_t bind(size_t index, float *out, const float *in);
130+
131+
/**
132+
* Bind input buffer to the channel.
133+
* @param index index of the channel
134+
* @param in input buffer. If input buffer is not specified, processing of the channel is disabled
135+
* @return status of operation
136+
*/
137+
status_t bind_in(size_t index, const float *in);
138+
139+
/**
140+
* Bind output buffer to the channel.
141+
* @param index index of the channel
142+
* @param out output buffer. If output buffer is not specified, back reverse FFT is not performed
143+
* @return status of operation
144+
*/
145+
status_t bind_out(size_t index, float *out);
146+
147+
/**
148+
* Unbind input and output buffers from specific channel
149+
* @param index index of the channel
150+
* @return status of operation
151+
*/
152+
status_t unbind(size_t index);
153+
154+
/**
155+
* Unbind input buffer from specific channel
156+
* @param index index of the channel
157+
* @return status of operation
158+
*/
159+
status_t unbind_in(size_t index);
160+
161+
/**
162+
* Unbind output buffer from specific channel
163+
* @param index index of the channel
164+
* @return status of operation
165+
*/
166+
status_t unbind_out(size_t index);
167+
168+
/**
169+
* Unbind all buffers
170+
* @param index index of the channel
171+
*/
172+
void unbind_all();
173+
174+
/**
175+
* Check that spectral processor needs update
176+
* @return true if spectral processor needs update
177+
*/
178+
inline bool needs_update() const { return bUpdate; }
179+
180+
/**
181+
* Update settings of the spectral processor
182+
*/
183+
void update_settings();
184+
185+
/**
186+
* Get the FFT rank
187+
* @return FFT rank
188+
*/
189+
inline size_t get_rank() const { return nRank; }
190+
191+
/**
192+
* Get processing phase
193+
* @return processing phase
194+
*/
195+
inline float phase() const { return fPhase; }
196+
197+
/**
198+
* Set processing phase
199+
* @param phase the phase value between 0 and 1
200+
*/
201+
void set_phase(float phase);
202+
203+
/**
204+
* Set the FFT rank
205+
*/
206+
void set_rank(size_t rank);
207+
208+
/**
209+
* Get latency of the spectral processor
210+
* @return latency of the spectral processor
211+
*/
212+
inline size_t latency() const { return 1 << nRank; }
213+
214+
/**
215+
* Perform audio processing
216+
* @param count number of samples to process
217+
*/
218+
void process(size_t count);
219+
220+
/**
221+
* Reset state: cleanup internal buffers
222+
*/
223+
void reset();
224+
225+
/**
226+
* Return number of samples remaining before the FFT transform operation occurs
227+
* @return number of samples remaining before the FFT transform occurs
228+
*/
229+
size_t remaining() const;
230+
231+
/**
232+
* Dump the state
233+
* @param v state dumper
234+
*/
235+
void dump(IStateDumper *v) const;
236+
};
237+
} /* namespace dspu */
238+
} /* namespace lsp */
239+
240+
241+
#endif /* LSP_PLUG_IN_DSP_UNITS_UTIL_MULTISPECTRALPROCESSOR_H_ */

src/main/util/Analyzer.cpp

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -466,7 +466,7 @@ namespace lsp
466466
void Analyzer::get_frequencies(float *frq, uint32_t *idx, float start, float stop, size_t count, bool linear)
467467
{
468468
const size_t fft_size = 1 << nRank;
469-
const size_t fft_csize = (fft_size >> 1) + 1;
469+
const size_t fft_width = (fft_size >> 1);
470470
const float scale = float(fft_size) / float(nSampleRate);
471471

472472
// Initialize list of frequencies depending on the scale
@@ -475,13 +475,9 @@ namespace lsp
475475
const float norm = (stop - start) / (count - 1);
476476
for (size_t i=0; i<count; ++i)
477477
{
478-
float f = start + i * norm;
479-
size_t ix = scale * f;
480-
if (ix > fft_csize)
481-
ix = fft_csize;
482-
483-
frq[i] = f;
484-
idx[i] = uint32_t(ix);
478+
const float f = start + i * norm;
479+
frq[i] = start + i * norm;
480+
idx[i] = lsp_min(scale * f, fft_width);
485481
}
486482
}
487483
else
@@ -490,13 +486,9 @@ namespace lsp
490486

491487
for (size_t i=0; i<count; ++i)
492488
{
493-
float f = start * expf(i * norm);
494-
size_t ix = scale * f;
495-
if (ix > fft_csize)
496-
ix = fft_csize;
497-
489+
const float f = start * expf(i * norm);
498490
frq[i] = f;
499-
idx[i] = uint32_t(ix);
491+
idx[i] = lsp_min(scale * f, fft_width);
500492
}
501493
}
502494
}

0 commit comments

Comments
 (0)