File: matcher.h

package info (click to toggle)
lsp-plugins 1.2.27-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 237,148 kB
  • sloc: cpp: 662,530; xml: 82,539; makefile: 14,305; php: 1,363; sh: 185
file content (537 lines) | stat: -rw-r--r-- 29,329 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
/*
 * Copyright (C) 2025 Linux Studio Plugins Project <https://lsp-plug.in/>
 *           (C) 2025 Vladimir Sadovnikov <sadko4u@gmail.com>
 *
 * This file is part of lsp-plugins-matcher
 * Created on: 02 ноя 2025 г.
 *
 * lsp-plugins-matcher is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 *
 * lsp-plugins-matcher 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 Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with lsp-plugins-matcher. If not, see <https://www.gnu.org/licenses/>.
 */

#ifndef PRIVATE_PLUGINS_MATCHER_H_
#define PRIVATE_PLUGINS_MATCHER_H_

#include <lsp-plug.in/dsp-units/ctl/Bypass.h>
#include <lsp-plug.in/dsp-units/ctl/Toggle.h>
#include <lsp-plug.in/dsp-units/util/Delay.h>
#include <lsp-plug.in/dsp-units/util/MultiSpectralProcessor.h>
#include <lsp-plug.in/dsp-units/sampling/Sample.h>
#include <lsp-plug.in/dsp-units/sampling/SamplePlayer.h>
#include <lsp-plug.in/plug-fw/core/IDBuffer.h>
#include <lsp-plug.in/plug-fw/plug.h>
#include <lsp-plug.in/lltl/state.h>
#include <private/meta/matcher.h>

namespace lsp
{
    namespace plugins
    {
        /**
         * Base class for the latency compensation delay
         */
        class matcher: public plug::Module
        {
            protected:
                enum processor_channel_t
                {
                    PC_INPUT,
                    PC_REFERENCE,
                    PC_CAPTURE,

                    PC_TOTAL
                };

                enum in_source_t
                {
                    IN_STATIC,              // Static input profile is used for matching
                    IN_DYNAMIC              // Dynamic input profile is used for matching
                };

                enum ref_source_t
                {
                    REF_NONE,
                    REF_CAPTURE,
                    REF_FILE,
                    REF_EQUALIZER,
                    REF_SIDECHAIN,
                    REF_LINK
                };

                enum raw_cap_source_t
                {
                    RAW_CAP_INPUT,          // Take spectral data from input channel
                    RAW_CAP_SIDECHAIN,      // Take spectral data from sidechain channel
                    RAW_CAP_LINK            // Take spectral data from shared memory link
                };

                enum cap_source_t
                {
                    CAP_NONE,               // No capture
                    CAP_INPUT,              // Take spectral data from input channel
                    CAP_SIDECHAIN,          // Take spectral data from sidechain channel
                    CAP_LINK,               // Take spectral data from shared memory link
                    CAP_REFERENCE           // Take spectral data from reference channel
                };

                enum sig_meters_t
                {
                    SM_IN,
                    SM_OUT,
                    SM_CAPTURE,
                    SM_REFERENCE,

                    SM_TOTAL
                };

                enum profile_type_t
                {
                    PROF_MATCH,             // Profile for matching curve, SR -> recompute
                    PROF_INPUT,             // Profile for the dynamic input audio, SR -> reset
                    PROF_REFERENCE,         // Profile for the dynamic reference audio, SR -> reset
                    PROF_STATIC,            // Profile for the static input audio, SR -> resample
                    PROF_CAPTURE,           // Profile for the static captured audio, SR -> resample
                    PROF_FILE,              // Profile for the file, SR -> re-render
                    PROF_ENVELOPE,          // Profile for the envelope, SR -> recompute
                    PROF_MIN_EQUALIZER,     // Profile for the minimum equalizer, SR -> recompute
                    PROF_MAX_EQUALIZER,     // Profile for the maximum equalizer, SR -> recompute

                    PROF_TOTAL
                };

                enum state_profile_type_t
                {
                    SPROF_STATIC,
                    SPROF_CAPTURE,
                    SPROF_FILE,

                    SPROF_TOTAL
                };

                enum kvt_profile_flags_t
                {
                    KVT_PFLAGS_NONE         = 0,
                    KVT_PFLAGS_READY        = 1 << 0,
                    KVT_PFLAGS_DEFAULT      = 1 << 1
                };

                enum profile_data_flags_t
                {
                    PFLAGS_NONE             = 0,
                    PFLAGS_DEFAULT          = 1 << 0,           // Default (empty) profile
                    PFLAGS_READY            = 1 << 1,           // Profile is ready for processing
                    PFLAGS_DIRTY            = 1 << 2,           // Profile is dirty and has not been saved
                    PFLAGS_CHANGED          = 1 << 3,           // Profile has been changed
                    PFLAGS_SYNC             = 1 << 4,           // Profile needs to be synchronized with UI
                    PFLAGS_NORMAL           = 1 << 5,           // Profile is filled with 0 dB amplification
                    PFLAGS_DYNAMIC          = 1 << 6,           // Profile is dynamically changing
                    PFLAGS_EMPTY            = 1 << 7,           // Profile is empty (level below the threshold)
                    PFLAGS_STATE            = 1 << 8,           // Profile is loaded from plugin state
                };

                enum eq_param_t
                {
                    EQP_REF_LEVEL,                              // Reference level
                    EQP_MAX_AMPLIFICATION,                      // Maximum amplification
                    EQP_MAX_REDUCTION,                          // Maximum reduction
                    EQP_REACTIVITY,                             // Reactvity

                    EQP_TOTAL
                };

                typedef struct profile_data_t
                {
                    uint32_t                nSampleRate;        // Sample rate of the profile
                    uint32_t                nChannels;          // Number of channels
                    uint32_t                nRank;              // FFT rank of the profile
                    uint32_t                nFlags;             // Profile data flags
                    uint32_t                nFrames;            // Number of frames collected
                    float                   fRMS;               // Profile loudness
                    float                 **vData;              // Sample data
                } profile_data_t;

                typedef struct af_descriptor_t
                {
                    dspu::Toggle        sListen;        // Listen toggle
                    dspu::Toggle        sStop;          // Stop toggle
                    dspu::Sample       *pOriginal;      // Original file sample
                    dspu::Sample       *pProcessed;     // Processed file sample
                    float              *vThumbs[2];     // Thumbnails
                    float               fNorm;          // Norming factor
                    status_t            nStatus;
                    bool                bSync;          // Synchronize file
                    bool                bCanListen;     // Can listen flag

                    float               fPitch;         // Pitch amount
                    float               fHeadCut;
                    float               fTailCut;
                    float               fDuration;      // Actual audio file duration

                    plug::IPort        *pShowOverlay;   // Port that shows file overlay
                    plug::IPort        *pFile;          // Port that contains file name
                    plug::IPort        *pPitch;         // Pitching amount in semitones
                    plug::IPort        *pHeadCut;       // Head cut of file
                    plug::IPort        *pTailCut;       // Tail cut of file
                    plug::IPort        *pListen;        // Listen event
                    plug::IPort        *pStop;          // Stop event
                    plug::IPort        *pStatus;        // Status of file loading
                    plug::IPort        *pLength;        // Length of file
                    plug::IPort        *pThumbs;        // Thumbnails of file
                    plug::IPort        *pPlayPosition;  // Output current playback position
                } af_descriptor_t;

                typedef struct channel_t
                {
                    // DSP processing modules
                    dspu::Bypass            sBypass;            // Bypass
                    dspu::SamplePlayer      sPlayer;            // Sample player
                    dspu::Playback          sPlayback;          // Sample playback
                    dspu::Delay             sDryDelay;          // Delay for dry (unprocessed) signal
                    dspu::Delay             sScDelay;           // Delay for sidechain signal

                    float                  *vIn;                // Input buffer
                    float                  *vOut;               // Output buffer
                    float                  *vSc;                // Sidechain buffer
                    float                  *vShmIn;             // Shared memory link
                    float                  *vFft[SM_TOTAL];     // FFT data
                    float                  *vBuffer;            // Temporary buffer
                    float                   vLevel[SM_TOTAL];   // Level meters

                    bool                    bFft[SM_TOTAL];     // Perform FFT processing

                    plug::IPort            *pIn;                // Input buffer
                    plug::IPort            *pOut;               // Output buffer
                    plug::IPort            *pSc;                // Sidechain buffer
                    plug::IPort            *pShmIn;             // Shared memory link

                    plug::IPort            *pFft[SM_TOTAL];     // Show FFT of signal
                    plug::IPort            *pMeter[SM_TOTAL];   // Level meter of signal
                } channel_t;

                typedef struct match_band_t
                {
                    float                   vParams[EQP_TOTAL]; // Equalizer parameters
                    plug::IPort            *pParams[EQP_TOTAL]; // Reference level
                } match_band_t;

                typedef struct kvt_profile_header_t
                {
                    uint16_t                nVersion;           // Version format of the BLOB
                    uint8_t                 nChannels;          // Number of channels
                    uint8_t                 nRank;              // FFT rank
                    uint32_t                nFlags;             // Flags
                    uint32_t                nSampleRate;        // Sample rate
                    uint32_t                nFrames;            // Frames
                    float                   fRMS;               // RMS
                } kvt_profile_header_t;

                // File loader
                class FileLoader: public ipc::ITask
                {
                    private:
                        matcher                *pCore;

                    public:
                        explicit FileLoader(matcher *core);
                        virtual ~FileLoader() override;

                    public:
                        virtual status_t run() override;

                        void        dump(dspu::IStateDumper *v) const;
                };

                // Preprocessing of audio file
                class FileProcessor: public ipc::ITask
                {
                    private:
                        matcher                *pCore;
                        bool                    bState;

                    public:
                        explicit FileProcessor(matcher *core);
                        virtual ~FileProcessor() override;

                    public:
                        virtual status_t run() override;
                        void            dump(dspu::IStateDumper *v) const;
                        inline void     set_state_flag(bool state)  { bState = state; }
                        inline bool     state_flag() const          { return bState; }
                };

                // Synchronization of profile data with KVT
                class KVTSync: public ipc::ITask, public core::KVTListener
                {
                    private:
                        matcher                *pCore;
                        profile_data_t         *vProfiles[SPROF_TOTAL];
                        size_t                  nChanges;
                        uatomic_t               nLocks;

                    protected:
                        void        parse_profile(const char *id, const core::kvt_param_t *param, uint32_t type, bool state);

                    public:
                        explicit KVTSync(matcher *core);
                        virtual ~KVTSync() override;

                    public:
                        status_t    init();
                        bool        submit_profile(uint32_t type, profile_data_t *profile);
                        bool        pending() const;
                        void        dump(dspu::IStateDumper *v) const;

                    public: // ipc::ITask
                        virtual status_t run() override;

                    public: // core::KVTListener
                        virtual void created(core::KVTStorage *storage, const char *id, const core::kvt_param_t *param, size_t pending) override;
                        virtual void changed(core::KVTStorage *storage, const char *id, const core::kvt_param_t *oval, const core::kvt_param_t *nval, size_t pending) override;
                        virtual void commit(core::KVTStorage *storage, const char *id, const core::kvt_param_t *param, size_t pending) override;
                };

                // Class to handle saving the IR file
                class IRSaver: public ipc::ITask
                {
                    private:
                        matcher        *pCore;
                        profile_data_t *pProfile;           // Profile to save
                        bool            bPending;           // Pending for save
                        char            sFile[PATH_MAX];    // The name of file for saving

                    public:
                        explicit IRSaver(matcher *base);
                        virtual ~IRSaver() override;

                    public:
                        status_t    init();
                        void        submit_command(bool save);
                        void        submit_profile(const profile_data_t *src);
                        void        submit_file_name(const char *fname);
                        bool        pending() const;
                        void        dump(dspu::IStateDumper *v) const;

                    public:
                        virtual status_t run() override;
                };

                // Garbage collection task
                class GCTask: public ipc::ITask
                {
                    private:
                        matcher                *pCore;

                    public:
                        explicit GCTask(matcher *base);
                        virtual ~GCTask() override;

                    public:
                        virtual status_t run() override;

                        void        dump(dspu::IStateDumper *v) const;
                };

            protected:
                uint32_t            nChannels;          // Number of channels
                channel_t          *vChannels;          // Delay channels
                uint32_t            nInSource;          // Input source
                uint32_t            nRefSource;         // Reference source
                uint32_t            nRawCapSource;      // Raw capture source
                uint32_t            nCapSource;         // Capture source
                uint32_t            nRank;              // FFT rank
                float               fGainIn;            // Input gain
                float               fGainOut;           // Output gain
                float               fFftTau;            // FFT time constant
                float               fFftShift;          // FFT shift
                float               fInTau;             // Input profile reactivity
                float               fRefTau;            // Reference profile reactivity
                float               fStereoLink;        // Stereo linking
                float               fBlend;             // Blend signal
                float               fHpfFreq;           // HPF frequency
                float               fHpfSlope;          // HPF slope
                float               fLpfFreq;           // LPF frequency
                float               fLpfSlope;          // LPF slope
                float               fClipFreq;          // Brickwall clipping frequency
                uint32_t            nFileProcessReq;    // File processing request
                uint32_t            nFileProcessResp;   // File processing response
                bool                bFileFromState;     // File from state
                bool                bSidechain;         // Sidechain flag
                bool                bProfile;           // Profile capturing is enabled
                bool                bCapture;           // Capture side signal
                bool                bListen;            // Listen signal
                bool                bSyncRefFFT;        // Synchronize reference FFT
                bool                bSyncFilter;        // Synchronize filter profile
                bool                bUpdateMatch;       // Update matching profile
                bool                bMatchTopLimit;     // Match limiting from top
                bool                bMatchBottomLimit;  // Match limiting from bottom

                dspu::MultiSpectralProcessor    sProcessor; // Multi-channel spectral processor
                dspu::Toggle        sMatchImmediate;    // Perform immediate matching
                af_descriptor_t     sFile;              // Audio file
                FileLoader          sFileLoader;        // Audio file loader
                FileProcessor       sFileProcessor;     // Audio file processor task
                KVTSync             sKVTSync;           // KVT synchronization task
                IRSaver             sIRSaver;           // Impulse response saver
                GCTask              sGCTask;            // Garbage collection task
                match_band_t        vMatchBands[meta::matcher::MATCH_BANDS];    // Match bands
                ipc::IExecutor     *pExecutor;          // Task executor
                dspu::Sample       *pGCList;            // Garbage collection list
                profile_data_t     *pReactivity;        // Reactivity profile
                profile_data_t     *pTempProfile;       // Temporary profile
                profile_data_t     *pFilterProfile;     // Filter profile
                profile_data_t     *pMatchProfile;      // Actual matching profile
                profile_data_t     *vProfileData[PROF_TOTAL];               // Profile data
                lltl::state<profile_data_t> vProfileState[SPROF_TOTAL];     // Record of the input profile

                uint16_t           *vIndices;           // FFT indices
                float              *vFreqs;             // FFT frequencies
                float              *vFilterCurve;       // Filter curve
                float              *vEnvelope;          // FFT envelope
                float              *vRevEnvelope;       // FFT reverse envelope
                float              *vBuffer;            // Temporary buffer
                float              *vEmptyBuf;          // Empty

                plug::IPort        *pBypass;            // Bypass
                plug::IPort        *pGainIn;            // Input gain
                plug::IPort        *pGainOut;           // Output gain
                plug::IPort        *pFftSize;           // FFT size
                plug::IPort        *pInReactivity;      // Input profile reactivity
                plug::IPort        *pRefReactivity;     // Reference profile reactivity
                plug::IPort        *pInSource;          // Input source
                plug::IPort        *pRefSource;         // Reference source
                plug::IPort        *pCapSource;         // Capture source
                plug::IPort        *pBlend;             // Blend signal
                plug::IPort        *pProfile;           // Start profiling
                plug::IPort        *pCapture;           // Enable capturing
                plug::IPort        *pListen;            // Listen capture
                plug::IPort        *pHpfOn;             // High-pass filter on
                plug::IPort        *pHpfFreq;           // High-pass filter frequency
                plug::IPort        *pHpfSlope;          // High-pass filter slope
                plug::IPort        *pLpfOn;             // Low-pass filter on
                plug::IPort        *pLpfFreq;           // Low-pass filter frequency
                plug::IPort        *pLpfSlope;          // Low-pass filter slope
                plug::IPort        *pClipOn;            // Brickwall clipping enabled
                plug::IPort        *pClipFreq;          // Brickwall clipping frequency
                plug::IPort        *pMatchInReady;      // Match input ready
                plug::IPort        *pMatchRefReady;     // Match reference ready
                plug::IPort        *pInReady;           // Input ready
                plug::IPort        *pCapReady;          // Capture ready
                plug::IPort        *pFileReady;         // Faile ready
                plug::IPort        *pFilterMesh;        // Filter mesh
                plug::IPort        *pStereoLink;        // Stereo link

                plug::IPort        *pIRFile;            // IR file name
                plug::IPort        *pIRSave;            // IR file save command
                plug::IPort        *pIRStatus;          // IR file save status
                plug::IPort        *pIRProgress;        // IR file save progress

                plug::IPort        *pMatchTopLimit;     // Enable frequency limiting from top
                plug::IPort        *pMatchBottomLimit;  // Enable frequency limiting from bottom
                plug::IPort        *pMatchLimit;        // Enable frequency limiting
                plug::IPort        *pMatchImmediate;    // Perform immediate matching
                plug::IPort        *pMatchMesh;         // Match mesh

                plug::IPort        *pFftReact;          // FFT reactivity for analysis
                plug::IPort        *pFftShift;          // FFT shift
                plug::IPort        *pFftMesh;           // Mesh for FFT analysis

                core::IDBuffer     *pIDisplay;          // Inline display buffer

                uint8_t            *pData;              // Allocated data

            protected:
                static void         dump(dspu::IStateDumper *v, const char *name, const profile_data_t * profile);
                static void         process_block(void *object, void *subject, float * const * spectrum, size_t rank);
                static void         process_sample_block(void *object, void *subject, float * const * spectrum, size_t rank);
                static void         free_profile_data(profile_data_t *profile);
                static void         destroy_sample(dspu::Sample * &s);
                static void         destroy_samples(dspu::Sample *gc_list);
                static bool         profile_is_relative(size_t profile);

            protected:
                void                do_destroy();
                inline void         set_profile_ready(plug::IPort *port, ssize_t id);
                profile_data_t     *allocate_profile_data(size_t channels = 0);
                profile_data_t     *create_default_profile(size_t channels = 0);
                void                init_buffers();
                void                bind_buffers(size_t samples);
                void                advance_buffers(size_t samples);
                void                update_frequency_mapping();
                void                output_fft_mesh_data();
                void                output_profile_mesh_data();
                void                output_file_mesh_data();
                void                output_filter_mesh_data();
                void                process_block(float * const * spectrum, size_t rank);
                void                analyze_spectrum(channel_t *c, sig_meters_t meter, const float *fft);
                uint32_t            decode_reference_source(size_t ref) const;
                uint32_t            decode_raw_capture_source(size_t cap) const;
                uint32_t            decode_capture_source(size_t raw_cap, size_t ref) const;
                bool                check_need_profile_sync();
                void                record_profile(profile_data_t *profile, float * const * spectrum, size_t channel);
                void                clear_profile_data(profile_data_t *profile);
                status_t            load_audio_file(af_descriptor_t *descr);
                status_t            process_audio_file();
                status_t            preprocess_sample(af_descriptor_t *f);
                status_t            profile_sample(af_descriptor_t *f);
                void                process_file_loading_tasks();
                void                process_file_processing_tasks();
                void                process_kvt_sync_tasks();
                void                process_gc_tasks();
                void                process_listen_events();
                void                process_save_ir_events();
                void                perform_gc();
                void                update_profiles();
                void                build_eq_profile(profile_data_t *profile, eq_param_t param, bool envelope);
                void                build_filter_profile();
                void                smooth_eq_curve(float *dst, float x1, float y1, float x2, float y2, size_t count);
                void                sync_profile(profile_data_t *dst, profile_data_t *src);
                inline void         sync_profile_with_state(profile_data_t *profile);
                void                post_process_profiles();
                void                track_profile(profile_data_t *profile, float * const * spectrum, float tau, size_t channel);
                void                build_match_profile(profile_data_t *in, profile_data_t *ref, bool dynamic);
                bool                resample_profile(profile_data_t *profile, size_t srate, size_t rank);
                void                commit_profiles();
                void                process_listen_output(channel_t *c, size_t samples);
                bool                save_profile(core::KVTStorage *kvt, const char *path, profile_data_t *profile);
                profile_data_t     *load_profile(const char *path, const core::kvt_param_t *param, bool state);
                void                init_level_meters();
                void                output_level_meters();
                void                output_profile_status();

            public:
                explicit matcher(const meta::plugin_t *meta);
                matcher (const matcher &) = delete;
                matcher (matcher &&) = delete;
                virtual ~matcher() override;

                matcher & operator = (const matcher &) = delete;
                matcher & operator = (matcher &&) = delete;

                virtual void        init(plug::IWrapper *wrapper, plug::IPort **ports) override;
                virtual void        destroy() override;

            public:
                virtual void        update_sample_rate(long sr) override;
                virtual void        update_settings() override;
                virtual void        process(size_t samples) override;
                virtual void        ui_activated() override;
                virtual void        dump(dspu::IStateDumper *v) const override;
                virtual bool        inline_display(plug::ICanvas *cv, size_t width, size_t height) override;
        };

    } /* namespace plugins */
} /* namespace lsp */


#endif /* PRIVATE_PLUGINS_MATCHER_H_ */