1 /*
2  * osclilloscope.cpp
3  *
4  *  Created on: 1 Mar 2020
5  *      Author: crocoduck
6  */
7 
8 #include <plugins/oscilloscope.h>
9 #include <core/debug.h>
10 #include <core/colors.h>
11 #include <core/util/Color.h>
12 
13 #define TRACE_PORT(p)       lsp_trace("  port id=%s", (p)->metadata()->id);
14 #define BUF_LIM_SIZE        196608
15 #define PRE_TRG_MAX_SIZE    196608
16 
17 #define SWEEP_GEN_N_BITS    32
18 #define SWEEP_GEN_PEAK      1.0f    /* Stream min x coordinate should be -SWEEP_GEN_PEAK and max x coordinate should be +SWEEP_GEN_PEAK */
19 
20 #define DC_BLOCK_CUTOFF_HZ  5.0
21 #define DC_BLOCK_DFL_ALPHA  0.999f
22 
23 #define STREAM_MAX_X        1.0f
24 #define STREAM_MIN_X       -1.0f
25 #define STREAM_MAX_Y        1.0f
26 #define STREAM_MIN_Y       -1.0f
27 #define STREAM_N_VER_DIV    4
28 #define STREAM_N_HOR_DIV    4
29 #define DECIM_PRECISION     0.1e-5  /* For development, this should be calculated from screen size */
30 #define IDISPLAY_DECIM      0.2e-2  /* Decimation for inline display */
31 
32 #define AUTO_SWEEP_TIME     1.0f
33 
34 namespace lsp
35 {
get_oversampler_mode(size_t portValue)36     over_mode_t oscilloscope_base::get_oversampler_mode(size_t portValue)
37     {
38         switch (portValue)
39         {
40             case oscilloscope_base_metadata::OSC_OVS_NONE:
41                 return OM_NONE;
42             case oscilloscope_base_metadata::OSC_OVS_2X:
43                 return OM_LANCZOS_2X4;
44             case oscilloscope_base_metadata::OSC_OVS_3X:
45                 return OM_LANCZOS_3X4;
46             case oscilloscope_base_metadata::OSC_OVS_4X:
47                 return OM_LANCZOS_4X4;
48             case oscilloscope_base_metadata::OSC_OVS_6X:
49                 return OM_LANCZOS_6X4;
50             case oscilloscope_base_metadata::OSC_OVS_8X:
51             default:
52                 return OM_LANCZOS_8X4;
53         }
54     }
55 
get_scope_mode(size_t portValue)56     oscilloscope_base::ch_mode_t oscilloscope_base::get_scope_mode(size_t portValue)
57     {
58         switch (portValue)
59         {
60             case oscilloscope_base_metadata::MODE_XY:
61                 return CH_MODE_XY;
62             case oscilloscope_base_metadata::MODE_TRIGGERED:
63                 return CH_MODE_TRIGGERED;
64             case oscilloscope_base_metadata::MODE_GONIOMETER:
65                 return CH_MODE_GONIOMETER;
66             default:
67                 return CH_MODE_DFL;
68         }
69     }
70 
get_sweep_type(size_t portValue)71     oscilloscope_base::ch_sweep_type_t oscilloscope_base::get_sweep_type(size_t portValue)
72     {
73         switch (portValue)
74         {
75             case oscilloscope_base_metadata::SWEEP_TYPE_SAWTOOTH:
76                 return CH_SWEEP_TYPE_SAWTOOTH;
77             case oscilloscope_base_metadata::SWEEP_TYPE_TRIANGULAR:
78                 return CH_SWEEP_TYPE_TRIANGULAR;
79             case oscilloscope_base_metadata::SWEEP_TYPE_SINE:
80                 return CH_SWEEP_TYPE_SINE;
81             default:
82                 return CH_SWEEP_TYPE_DFL;
83         }
84     }
85 
get_trigger_input(size_t portValue)86     oscilloscope_base::ch_trg_input_t oscilloscope_base::get_trigger_input(size_t portValue)
87     {
88         switch (portValue)
89         {
90             case oscilloscope_base_metadata::TRIGGER_INPUT_Y:
91                 return CH_TRG_INPUT_Y;
92             case oscilloscope_base_metadata::TRIGGER_INPUT_EXT:
93                 return CH_TRG_INPUT_EXT;
94             default:
95                 return CH_TRG_INPUT_DFL;
96         }
97     }
98 
get_coupling_type(size_t portValue)99     oscilloscope_base::ch_coupling_t oscilloscope_base::get_coupling_type(size_t portValue)
100     {
101         switch (portValue)
102         {
103             case oscilloscope_base_metadata::COUPLING_AC:
104                 return CH_COUPLING_AC;
105             case oscilloscope_base_metadata::COUPLING_DC:
106                 return CH_COUPLING_DC;
107             default:
108                 return CH_COUPLING_DFL;
109 
110         }
111     }
112 
get_trigger_mode(size_t portValue)113     trg_mode_t oscilloscope_base::get_trigger_mode(size_t portValue)
114     {
115         switch (portValue)
116         {
117             case oscilloscope_base_metadata::TRIGGER_MODE_SINGLE:
118                 return TRG_MODE_SINGLE;
119             case  oscilloscope_base_metadata::TRIGGER_MODE_MANUAL:
120                 return TRG_MODE_MANUAL;
121             case oscilloscope_base_metadata::TRIGGER_MODE_REPEAT:
122                 return TRG_MODE_REPEAT;
123             default:
124                 return TRG_MODE_REPEAT;
125         }
126     }
127 
get_trigger_type(size_t portValue)128     trg_type_t oscilloscope_base::get_trigger_type(size_t portValue)
129     {
130         switch (portValue)
131         {
132             case oscilloscope_base_metadata::TRIGGER_TYPE_NONE:
133                 return TRG_TYPE_NONE;
134             case oscilloscope_base_metadata::TRIGGER_TYPE_SIMPLE_RISING_EDGE:
135                 return TRG_TYPE_SIMPLE_RISING_EDGE;
136             case oscilloscope_base_metadata::TRIGGER_TYPE_SIMPE_FALLING_EDGE:
137                 return TRG_TYPE_SIMPLE_FALLING_EDGE;
138             case oscilloscope_base_metadata::TRIGGER_TYPE_ADVANCED_RISING_EDGE:
139                 return TRG_TYPE_ADVANCED_RISING_EDGE;
140             case oscilloscope_base_metadata::TRIGGER_TYPE_ADVANCED_FALLING_EDGE:
141                 return TRG_TYPE_ADVANCED_FALLING_EDGE;
142             default:
143                 return TRG_TYPE_NONE;
144         }
145     }
146 
update_dc_block_filter(FilterBank & rFilterBank)147     void oscilloscope_base::update_dc_block_filter(FilterBank &rFilterBank)
148     {
149         /* Filter Transfer Function:
150          *
151          *          g - g z^-1
152          * H(z) = ----------------
153          *          1 - a * z^-1
154          *
155          * With g = sDCBlockParams.fGain, a = sACBlockParams.fAlpha
156          */
157 
158         rFilterBank.begin();
159 
160         biquad_x1_t *f = rFilterBank.add_chain();
161         if (f == NULL)
162             return;
163 
164         f->b0   = sDCBlockParams.fGain;
165         f->b1   = -sDCBlockParams.fGain;
166         f->b2   = 0.0f;
167         f->a1   = sDCBlockParams.fAlpha;
168         f->a2   = 0.0f;
169         f->p0   = 0.0f;
170         f->p1   = 0.0f;
171         f->p2   = 0.0f;
172 
173         rFilterBank.end(true);
174     }
175 
reconfigure_dc_block_filters()176     void oscilloscope_base::reconfigure_dc_block_filters()
177     {
178         double omega = 2.0 * M_PI * DC_BLOCK_CUTOFF_HZ / fSampleRate; // Normalised frequency
179 
180         double c = cos(omega);
181         double g = 1.9952623149688795; // This is 10^(3/10), used to calculate the parameter alpha so that it is exactly associated to the cutoff frequency (-3 dB).
182         double r = sqrt(c*c - 1.0 - 2.0 * g * c + 2.0 * g);
183 
184         double alpha1 = c + r;
185         double alpha2 = c - r;
186 
187         if ((alpha1 >= 0.0) && (alpha1 < 1.0))
188             sDCBlockParams.fAlpha = alpha1;
189         else if ((alpha2 >= 0.0) && (alpha2 < 1.0))
190             sDCBlockParams.fAlpha = alpha2;
191         else
192             sDCBlockParams.fAlpha = DC_BLOCK_DFL_ALPHA;
193 
194         sDCBlockParams.fGain = 0.5f * (1.0f + sDCBlockParams.fAlpha);
195 
196         for (size_t ch = 0; ch < nChannels; ++ch)
197         {
198             channel_t *c = &vChannels[ch];
199 
200             update_dc_block_filter(c->sDCBlockBank_x);
201             update_dc_block_filter(c->sDCBlockBank_y);
202             update_dc_block_filter(c->sDCBlockBank_ext);
203         }
204     }
205 
do_sweep_step(channel_t * c,float strobe_value)206     void oscilloscope_base::do_sweep_step(channel_t *c, float strobe_value)
207     {
208         c->sSweepGenerator.process_overwrite(&c->vDisplay_x[c->nDisplayHead], 1);
209         c->vDisplay_y[c->nDisplayHead] = c->vData_y_delay[c->nDataHead];
210         c->vDisplay_s[c->nDisplayHead] = strobe_value;
211         ++c->nDataHead;
212         ++c->nDisplayHead;
213     }
214 
select_trigger_input(float * extPtr,float * yPtr,ch_trg_input_t input)215     float *oscilloscope_base::select_trigger_input(float *extPtr, float* yPtr, ch_trg_input_t input)
216     {
217         switch (input)
218         {
219             case CH_TRG_INPUT_EXT:
220                 return extPtr;
221 
222             case CH_TRG_INPUT_Y:
223             default:
224                 return yPtr;
225         }
226     }
227 
set_oversampler(Oversampler & over,over_mode_t mode)228     void oscilloscope_base::set_oversampler(Oversampler &over, over_mode_t mode)
229     {
230         over.set_mode(mode);
231         if (over.modified())
232             over.update_settings();
233     }
234 
set_sweep_generator(channel_t * c)235     void oscilloscope_base::set_sweep_generator(channel_t *c)
236     {
237         c->sSweepGenerator.set_sample_rate(c->nOverSampleRate);
238         c->sSweepGenerator.set_frequency(c->nOverSampleRate / c->nSweepSize);
239 
240         switch (c->enSweepType)
241         {
242             case CH_SWEEP_TYPE_TRIANGULAR:
243             {
244                 c->sSweepGenerator.set_function(FG_SAWTOOTH);
245                 c->sSweepGenerator.set_dc_reference(DC_WAVEDC);
246                 c->sSweepGenerator.set_amplitude(SWEEP_GEN_PEAK);
247                 c->sSweepGenerator.set_dc_offset(0.0f);
248                 c->sSweepGenerator.set_width(0.5f);
249             }
250             break;
251 
252             case CH_SWEEP_TYPE_SINE:
253             {
254                 c->sSweepGenerator.set_function(FG_SINE);
255                 c->sSweepGenerator.set_dc_reference(DC_WAVEDC);
256                 c->sSweepGenerator.set_amplitude(SWEEP_GEN_PEAK);
257                 c->sSweepGenerator.set_dc_offset(0.0f);
258             }
259             break;
260 
261             case CH_SWEEP_TYPE_SAWTOOTH:
262             default:
263             {
264                 c->sSweepGenerator.set_function(FG_SAWTOOTH);
265                 c->sSweepGenerator.set_dc_reference(DC_WAVEDC);
266                 c->sSweepGenerator.set_amplitude(SWEEP_GEN_PEAK);
267                 c->sSweepGenerator.set_dc_offset(0.0f);
268                 c->sSweepGenerator.set_width(1.0f);
269             }
270             break;
271         }
272 
273         c->sSweepGenerator.update_settings();
274     }
275 
configure_oversamplers(channel_t * c,over_mode_t mode)276     void oscilloscope_base::configure_oversamplers(channel_t *c, over_mode_t mode)
277     {
278         c->enOverMode = mode;
279 
280         set_oversampler(c->sOversampler_x, c->enOverMode);
281         set_oversampler(c->sOversampler_y, c->enOverMode);
282         set_oversampler(c->sOversampler_ext, c->enOverMode);
283 
284         // All are set the same way, use any to get these variables
285         c->nOversampling    = c->sOversampler_x.get_oversampling();
286         c->nOverSampleRate  = c->nOversampling * fSampleRate;
287     }
288 
oscilloscope_base(const plugin_metadata_t & metadata,size_t channels)289     oscilloscope_base::oscilloscope_base(const plugin_metadata_t &metadata, size_t channels): plugin_t(metadata)
290     {
291         nChannels           = channels;
292         vChannels           = NULL;
293 
294         pData               = NULL;
295 
296         pStrobeHistSize     = NULL;
297         pXYRecordTime       = NULL;
298         pFreeze             = NULL;
299 
300         pChannelSelector    = NULL;
301 
302         pOvsMode            = NULL;
303         pScpMode            = NULL;
304         pCoupling_x         = NULL;
305         pCoupling_y         = NULL;
306         pCoupling_ext       = NULL;
307 
308         pSweepType          = NULL;
309         pTimeDiv            = NULL;
310         pHorDiv             = NULL;
311         pHorPos             = NULL;
312 
313         pVerDiv             = NULL;
314         pVerPos             = NULL;
315 
316         pTrgHys             = NULL;
317         pTrgLev             = NULL;
318         pTrgHold            = NULL;
319         pTrgMode            = NULL;
320         pTrgType            = NULL;
321         pTrgInput           = NULL;
322         pTrgReset           = NULL;
323 
324         pIDisplay           = NULL;
325     }
326 
~oscilloscope_base()327     oscilloscope_base::~oscilloscope_base()
328     {
329     }
330 
destroy()331     void oscilloscope_base::destroy()
332     {
333         free_aligned(pData);
334         pData = NULL;
335 
336         if (vChannels != NULL)
337         {
338             for (size_t ch = 0; ch < nChannels; ++ch)
339             {
340                 channel_t *c = &vChannels[ch];
341 
342                 c->sDCBlockBank_x.destroy();
343                 c->sDCBlockBank_y.destroy();
344                 c->sDCBlockBank_ext.destroy();
345 
346                 c->sOversampler_x.destroy();
347                 c->sOversampler_y.destroy();
348                 c->sOversampler_ext.destroy();
349 
350                 c->sPreTrgDelay.destroy();
351 
352                 c->sSweepGenerator.destroy();
353 
354                 c->vTemp            = NULL;
355                 c->vData_x          = NULL;
356                 c->vData_y          = NULL;
357                 c->vData_ext        = NULL;
358                 c->vData_y_delay    = NULL;
359                 c->vDisplay_x       = NULL;
360                 c->vDisplay_y       = NULL;
361                 c->vDisplay_s       = NULL;
362 
363                 c->vIDisplay_x      = NULL;
364                 c->vIDisplay_y      = NULL;
365             }
366 
367             delete [] vChannels;
368             vChannels = NULL;
369         }
370 
371         if (pIDisplay != NULL)
372         {
373             pIDisplay->detroy();
374             pIDisplay   = NULL;
375         }
376     }
377 
init(IWrapper * wrapper)378     void oscilloscope_base::init(IWrapper *wrapper)
379     {
380         plugin_t::init(wrapper);
381 
382         vChannels = new channel_t[nChannels];
383         if (vChannels == NULL)
384             return;
385 
386         /** For each channel:
387          * 1X temp buffer +
388          * 1X external data buffer +
389          * 1X x data buffer +
390          * 1X y data buffer +
391          * 1X delayed y data buffer +
392          * 1X x display buffer +
393          * 1X y display buffer +
394          * 1X strobe display buffer
395          * 1X x inline display buffer
396          * 1X y inline display buffer
397          *
398          * All buffers size BUF_LIM_SIZE
399          */
400         size_t samples = nChannels * BUF_LIM_SIZE * 10;
401 
402         float *ptr = alloc_aligned<float>(pData, samples);
403         if (ptr == NULL)
404             return;
405 
406         lsp_guard_assert(float *save = ptr);
407 
408         for (size_t ch = 0; ch < nChannels; ++ch)
409         {
410             channel_t *c = &vChannels[ch];
411 
412             init_state_stage(c);
413 
414             if (!c->sDCBlockBank_x.init(FILTER_CHAINS_MAX))
415                 return;
416 
417             if (!c->sDCBlockBank_y.init(FILTER_CHAINS_MAX))
418                 return;
419 
420             if (!c->sDCBlockBank_ext.init(FILTER_CHAINS_MAX))
421                 return;
422 
423             if (!c->sOversampler_x.init())
424                 return;
425 
426             if (!c->sOversampler_y.init())
427                 return;
428 
429             if (!c->sOversampler_ext.init())
430                 return;
431 
432             if (!c->sPreTrgDelay.init(PRE_TRG_MAX_SIZE))
433                 return;
434 
435             // Settings for the Sweep Generator
436             c->sSweepGenerator.init();
437             c->sSweepGenerator.set_phase_accumulator_bits(SWEEP_GEN_N_BITS);
438             c->sSweepGenerator.set_phase(0.0f);
439             c->sSweepGenerator.update_settings();
440 
441             c->vTemp            = ptr;
442             ptr                += BUF_LIM_SIZE;
443 
444             c->vData_x          = ptr;
445             ptr                += BUF_LIM_SIZE;
446 
447             c->vData_y          = ptr;
448             ptr                += BUF_LIM_SIZE;
449 
450             c->vData_ext        = ptr;
451             ptr                += BUF_LIM_SIZE;
452 
453             c->vData_y_delay    = ptr;
454             ptr                += BUF_LIM_SIZE;
455 
456             c->vDisplay_x       = ptr;
457             ptr                += BUF_LIM_SIZE;
458 
459             c->vDisplay_y       = ptr;
460             ptr                += BUF_LIM_SIZE;
461 
462             c->vDisplay_s       = ptr;
463             ptr                += BUF_LIM_SIZE;
464 
465             c->vIDisplay_x      = ptr;
466             ptr                += BUF_LIM_SIZE;
467 
468             c->vIDisplay_y      = ptr;
469             ptr                += BUF_LIM_SIZE;
470 
471             c->nIDisplay            = 0;
472 
473             c->nDataHead            = 0;
474             c->nDisplayHead         = 0;
475             c->nSamplesCounter      = 0;
476             c->bClearStream         = false;
477 
478             c->nPreTrigger          = 0;
479             c->nSweepSize           = 0;
480 
481             c->fVerStreamScale      = 0.0f;
482             c->fVerStreamOffset     = 0.0f;
483 
484             c->bAutoSweep           = true;
485             c->nAutoSweepLimit      = 0;
486             c->nAutoSweepCounter    = 0;
487 
488             c->enState              = CH_STATE_LISTENING;
489 
490             c->vIn_x                = NULL;
491             c->vIn_y                = NULL;
492             c->vIn_ext              = NULL;
493 
494             c->vOut_x               = NULL;
495             c->vOut_y               = NULL;
496 
497             c->pIn_x                = NULL;
498             c->pIn_y                = NULL;
499             c->pIn_ext              = NULL;
500 
501             c->pOut_x               = NULL;
502             c->pOut_y               = NULL;
503 
504             c->pOvsMode             = NULL;
505             c->pScpMode             = NULL;
506             c->pCoupling_x          = NULL;
507             c->pCoupling_y          = NULL;
508             c->pCoupling_ext        = NULL;
509 
510             c->pSweepType           = NULL;
511             c->pTimeDiv             = NULL;
512             c->pHorPos              = NULL;
513 
514             c->pVerDiv              = NULL;
515             c->pVerPos              = NULL;
516 
517             c->pTrgHys              = NULL;
518             c->pTrgLev              = NULL;
519             c->pTrgHold             = NULL;
520             c->pTrgMode             = NULL;
521             c->pTrgType             = NULL;
522             c->pTrgInput            = NULL;
523             c->pTrgReset            = NULL;
524 
525             c->pGlobalSwitch        = NULL;
526             c->pFreezeSwitch        = NULL;
527             c->pSoloSwitch          = NULL;
528             c->pMuteSwitch          = NULL;
529 
530             c->pStream              = NULL;
531         }
532 
533         lsp_assert(ptr <= &save[samples]);
534 
535         // Bind ports
536         size_t port_id = 0;
537 
538         lsp_trace("Binding audio ports");
539 
540         for (size_t ch = 0; ch < nChannels; ++ch)
541         {
542             TRACE_PORT(vPorts[port_id]);
543             vChannels[ch].pIn_x = vPorts[port_id++];
544 
545             TRACE_PORT(vPorts[port_id]);
546             vChannels[ch].pIn_y = vPorts[port_id++];
547 
548             TRACE_PORT(vPorts[port_id]);
549             vChannels[ch].pIn_ext = vPorts[port_id++];
550 
551             TRACE_PORT(vPorts[port_id]);
552             vChannels[ch].pOut_x = vPorts[port_id++];
553 
554             TRACE_PORT(vPorts[port_id]);
555             vChannels[ch].pOut_y = vPorts[port_id++];
556         }
557 
558         // Common settings
559         lsp_trace("Binding common ports");
560 
561         TRACE_PORT(vPorts[port_id]);
562         pStrobeHistSize = vPorts[port_id++];
563 
564         TRACE_PORT(vPorts[port_id]);
565         pXYRecordTime   = vPorts[port_id++];
566 
567         TRACE_PORT(vPorts[port_id]);
568         ++port_id;      // Skip 'maxdots' parameter
569 
570         TRACE_PORT(vPorts[port_id]);
571         pFreeze         = vPorts[port_id++];
572 
573         // Channel selector only exists on multi-channel versions. Skip for 1X plugin.
574         if (nChannels > 1)
575         {
576             TRACE_PORT(vPorts[port_id]);
577             pChannelSelector = vPorts[port_id++];
578         }
579 
580         // Global ports only exists on multi-channel versions. Skip for 1X plugin.
581 
582         if (nChannels > 1)
583         {
584             lsp_trace("Binding global control ports");
585 
586             TRACE_PORT(vPorts[port_id]);
587             pOvsMode = vPorts[port_id++];
588 
589             TRACE_PORT(vPorts[port_id]);
590             pScpMode = vPorts[port_id++];
591 
592             TRACE_PORT(vPorts[port_id]);
593             pCoupling_x = vPorts[port_id++];
594 
595             TRACE_PORT(vPorts[port_id]);
596             pCoupling_y = vPorts[port_id++];
597 
598             TRACE_PORT(vPorts[port_id]);
599             pCoupling_ext = vPorts[port_id++];
600 
601             TRACE_PORT(vPorts[port_id]);
602             pSweepType = vPorts[port_id++];
603 
604             TRACE_PORT(vPorts[port_id]);
605             pTimeDiv = vPorts[port_id++];
606 
607             TRACE_PORT(vPorts[port_id]);
608             pHorDiv = vPorts[port_id++];
609 
610             TRACE_PORT(vPorts[port_id]);
611             pHorPos = vPorts[port_id++];
612 
613             TRACE_PORT(vPorts[port_id]);
614             pVerDiv = vPorts[port_id++];
615 
616             TRACE_PORT(vPorts[port_id]);
617             pVerPos = vPorts[port_id++];
618 
619             TRACE_PORT(vPorts[port_id]);
620             pTrgHys = vPorts[port_id++];
621 
622             TRACE_PORT(vPorts[port_id]);
623             pTrgLev = vPorts[port_id++];
624 
625             TRACE_PORT(vPorts[port_id]);
626             pTrgHold = vPorts[port_id++];
627 
628             TRACE_PORT(vPorts[port_id]);
629             pTrgMode = vPorts[port_id++];
630 
631             TRACE_PORT(vPorts[port_id]);
632             pTrgType = vPorts[port_id++];
633 
634             TRACE_PORT(vPorts[port_id]);
635             pTrgInput = vPorts[port_id++];
636 
637             TRACE_PORT(vPorts[port_id]);
638             pTrgReset = vPorts[port_id++];
639         }
640 
641         lsp_trace("Binding channel control ports");
642 
643 
644         for (size_t ch = 0; ch < nChannels; ++ch)
645         {
646             TRACE_PORT(vPorts[port_id]);
647             vChannels[ch].pOvsMode = vPorts[port_id++];
648 
649             TRACE_PORT(vPorts[port_id]);
650             vChannels[ch].pScpMode = vPorts[port_id++];
651 
652             TRACE_PORT(vPorts[port_id]);
653             vChannels[ch].pCoupling_x = vPorts[port_id++];
654 
655             TRACE_PORT(vPorts[port_id]);
656             vChannels[ch].pCoupling_y = vPorts[port_id++];
657 
658             TRACE_PORT(vPorts[port_id]);
659             vChannels[ch].pCoupling_ext = vPorts[port_id++];
660 
661             TRACE_PORT(vPorts[port_id]);
662             vChannels[ch].pSweepType = vPorts[port_id++];
663 
664             TRACE_PORT(vPorts[port_id]);
665             vChannels[ch].pTimeDiv = vPorts[port_id++];
666 
667             TRACE_PORT(vPorts[port_id]);
668             vChannels[ch].pHorDiv = vPorts[port_id++];
669 
670             TRACE_PORT(vPorts[port_id]);
671             vChannels[ch].pHorPos = vPorts[port_id++];
672 
673             TRACE_PORT(vPorts[port_id]);
674             vChannels[ch].pVerDiv = vPorts[port_id++];
675 
676             TRACE_PORT(vPorts[port_id]);
677             vChannels[ch].pVerPos = vPorts[port_id++];
678 
679             TRACE_PORT(vPorts[port_id]);
680             vChannels[ch].pTrgHys = vPorts[port_id++];
681 
682             TRACE_PORT(vPorts[port_id]);
683             vChannels[ch].pTrgLev = vPorts[port_id++];
684 
685             TRACE_PORT(vPorts[port_id]);
686             vChannels[ch].pTrgHold = vPorts[port_id++];
687 
688             TRACE_PORT(vPorts[port_id]);
689             vChannels[ch].pTrgMode = vPorts[port_id++];
690 
691             TRACE_PORT(vPorts[port_id]);
692             vChannels[ch].pTrgType = vPorts[port_id++];
693 
694             TRACE_PORT(vPorts[port_id]);
695             vChannels[ch].pTrgInput = vPorts[port_id++];
696 
697             TRACE_PORT(vPorts[port_id]);
698             vChannels[ch].pTrgReset = vPorts[port_id++];
699         }
700 
701         lsp_trace("Binding channel switches ports");
702 
703         if (nChannels > 1)
704         {
705             for (size_t ch = 0; ch < nChannels; ++ch)
706             {
707                 TRACE_PORT(vPorts[port_id]);
708                 vChannels[ch].pGlobalSwitch = vPorts[port_id++];
709 
710                 TRACE_PORT(vPorts[port_id]);
711                 vChannels[ch].pFreezeSwitch = vPorts[port_id++];
712 
713                 TRACE_PORT(vPorts[port_id]);
714                 vChannels[ch].pSoloSwitch = vPorts[port_id++];
715 
716                 TRACE_PORT(vPorts[port_id]);
717                 vChannels[ch].pMuteSwitch = vPorts[port_id++];
718             }
719         }
720 
721         lsp_trace("Binding channel visual outputs ports");
722 
723         for (size_t ch = 0; ch < nChannels; ++ch)
724         {
725             TRACE_PORT(vPorts[port_id]);
726             vChannels[ch].pStream = vPorts[port_id++];
727         }
728     }
729 
init_state_stage(channel_t * c)730     void oscilloscope_base::init_state_stage(channel_t *c)
731     {
732         c->nUpdate = 0;
733 
734         c->sStateStage.nPV_pScpMode = oscilloscope_base_metadata::MODE_DFL;
735         c->nUpdate |= UPD_SCPMODE;
736 
737         c->sStateStage.nPV_pCoupling_x = oscilloscope_base_metadata::COUPLING_DFL;
738         c->nUpdate |= UPD_ACBLOCK_X;
739 
740         c->sStateStage.nPV_pCoupling_y = oscilloscope_base_metadata::COUPLING_DFL;
741         c->nUpdate |= UPD_ACBLOCK_Y;
742 
743         c->sStateStage.nPV_pCoupling_ext = oscilloscope_base_metadata::COUPLING_DFL;
744         c->nUpdate |= UPD_ACBLOCK_EXT;
745 
746         c->sStateStage.nPV_pOvsMode = oscilloscope_base_metadata::OSC_OVS_DFL;
747         c->nUpdate |= UPD_OVERSAMPLER_X;
748         c->nUpdate |= UPD_OVERSAMPLER_Y;
749         c->nUpdate |= UPD_OVERSAMPLER_EXT;
750 
751         c->sStateStage.nPV_pTrgInput = oscilloscope_base_metadata::TRIGGER_INPUT_DFL;
752         c->nUpdate |= UPD_TRIGGER_INPUT;
753 
754         c->sStateStage.fPV_pVerDiv = oscilloscope_base_metadata::VERTICAL_DIVISION_DFL;
755         c->sStateStage.fPV_pVerPos = oscilloscope_base_metadata::VERTICAL_POSITION_DFL;
756         c->nUpdate |= UPD_TRIGGER;
757 
758         c->sStateStage.fPV_pTrgHys = oscilloscope_base_metadata::TRIGGER_HYSTERESIS_DFL;
759         c->nUpdate |= UPD_TRIGGER;
760 
761         c->sStateStage.fPV_pTrgLevel = oscilloscope_base_metadata::TRIGGER_LEVEL_DFL;
762         c->nUpdate |= UPD_TRIGGER;
763 
764         c->sStateStage.nPV_pTrgMode = oscilloscope_base_metadata::TRIGGER_MODE_DFL;
765         c->nUpdate |= UPD_TRIGGER;
766 
767         c->sStateStage.fPV_pTrgHold = oscilloscope_base_metadata::TRIGGER_HOLD_TIME_DFL;
768         c->nUpdate |= UPD_TRIGGER_HOLD;
769 
770         c->sStateStage.nPV_pTrgType = oscilloscope_base_metadata::TRIGGER_TYPE_DFL;
771         c->nUpdate |= UPD_TRIGGER;
772 
773         c->sStateStage.fPV_pTimeDiv = oscilloscope_base_metadata::TIME_DIVISION_DFL;
774         c->nUpdate |= UPD_SWEEP_GENERATOR;
775 
776         c->sStateStage.fPV_pHorPos = oscilloscope_base_metadata::TIME_POSITION_DFL;
777         c->nUpdate |= UPD_SWEEP_GENERATOR;
778         c->nUpdate |= UPD_PRETRG_DELAY;
779 
780         c->sStateStage.nPV_pSweepType = oscilloscope_base_metadata::SWEEP_TYPE_DFL;
781         c->nUpdate |= UPD_SWEEP_GENERATOR;
782 
783         c->sStateStage.fPV_pXYRecordTime = oscilloscope_base_metadata::XY_RECORD_TIME_DFL;
784         c->nUpdate |= UPD_XY_RECORD_TIME;
785 
786         c->nUpdate |= UPD_VER_SCALES;
787         c->nUpdate |= UPD_HOR_SCALES;
788 
789         // By default, this must be false.
790         c->bUseGlobal   = false;
791         c->bFreeze      = false;
792         c->bVisible     = false;
793     }
794 
commit_staged_state_change(channel_t * c)795     void oscilloscope_base::commit_staged_state_change(channel_t *c)
796     {
797         if (c->nUpdate == 0)
798             return;
799 
800         if (c->nUpdate & UPD_SCPMODE)
801         {
802             c->enMode           = get_scope_mode(c->sStateStage.nPV_pScpMode);
803             c->nDisplayHead     = 0;    // Reset the display head
804         }
805 
806         if (c->nUpdate & UPD_ACBLOCK_X)
807             c->enCoupling_x = get_coupling_type(c->sStateStage.nPV_pCoupling_x);
808 
809         if (c->nUpdate & UPD_ACBLOCK_Y)
810             c->enCoupling_y = get_coupling_type(c->sStateStage.nPV_pCoupling_y);
811 
812         if (c->nUpdate & UPD_ACBLOCK_EXT)
813             c->enCoupling_ext = get_coupling_type(c->sStateStage.nPV_pCoupling_ext);
814 
815         if (c->nUpdate & (UPD_OVERSAMPLER_X | UPD_OVERSAMPLER_Y | UPD_OVERSAMPLER_EXT))
816             configure_oversamplers(c, get_oversampler_mode(c->sStateStage.nPV_pOvsMode));
817 
818         if (c->nUpdate & UPD_XY_RECORD_TIME)
819         {
820             c->nXYRecordSize = millis_to_samples(c->nOverSampleRate, c->sStateStage.fPV_pXYRecordTime);
821             c->nXYRecordSize = (c->nXYRecordSize < BUF_LIM_SIZE) ? c->nXYRecordSize  : BUF_LIM_SIZE;
822         }
823 
824         // UPD_SWEEP_GENERATOR handling is split because if also UPD_PRETRG_DELAY needs to be handled them the correct order of operations is as follows.
825         if (c->nUpdate & UPD_SWEEP_GENERATOR)
826         {
827             c->nSweepSize = STREAM_N_HOR_DIV * millis_to_samples(c->nOverSampleRate, c->sStateStage.fPV_pTimeDiv);
828             c->nSweepSize = (c->nSweepSize < BUF_LIM_SIZE) ? c->nSweepSize  : BUF_LIM_SIZE;
829         }
830 
831         if (c->nUpdate & UPD_PRETRG_DELAY)
832         {
833             c->nPreTrigger = 0.5f * (0.01f * c->sStateStage.fPV_pHorPos  + 1) * (c->nSweepSize - 1);
834             c->nPreTrigger = (c->nPreTrigger < PRE_TRG_MAX_SIZE) ? c->nPreTrigger : PRE_TRG_MAX_SIZE;
835             c->sPreTrgDelay.set_delay(c->nPreTrigger);
836             c->sPreTrgDelay.clear();
837         }
838 
839         if (c->nUpdate & UPD_SWEEP_GENERATOR)
840         {
841             c->enSweepType = get_sweep_type(c->sStateStage.nPV_pSweepType);
842             set_sweep_generator(c);
843 
844             // Since the seep period has changed, we need to revert state to LISTENING.
845             c->enState = CH_STATE_LISTENING;
846         }
847 
848         if (c->nUpdate & UPD_TRIGGER_INPUT)
849             c->enTrgInput = get_trigger_input(c->sStateStage.nPV_pTrgInput);
850 
851         if (c->nUpdate & UPD_TRIGGER_HOLD)
852         {
853             size_t minHold = c->nSweepSize;
854             size_t trgHold = seconds_to_samples(c->nOverSampleRate, c->sStateStage.fPV_pTrgHold);
855             trgHold = trgHold > minHold ? trgHold : minHold;
856             c->sTrigger.set_trigger_hold_samples(trgHold);
857 
858             c->nAutoSweepLimit      = seconds_to_samples(c->nOverSampleRate, AUTO_SWEEP_TIME);
859             c->nAutoSweepLimit      = (c->nAutoSweepLimit < trgHold) ? trgHold: c->nAutoSweepLimit;
860             c->nAutoSweepCounter    = 0;
861         }
862 
863         if (c->nUpdate & UPD_HOR_SCALES)
864         {
865             c->fHorStreamScale      = (STREAM_MAX_X - STREAM_MIN_X) / (STREAM_N_HOR_DIV * c->sStateStage.fPV_pHorDiv);
866             c->fHorStreamOffset     = 0.5f * (STREAM_MAX_X - STREAM_MIN_X) * (0.01f * c->sStateStage.fPV_pHorPos + 1.0f) + STREAM_MIN_X;
867         }
868 
869         if (c->nUpdate & UPD_VER_SCALES)
870         {
871             c->fVerStreamScale      = (STREAM_MAX_Y - STREAM_MIN_Y) / (STREAM_N_VER_DIV * c->sStateStage.fPV_pVerDiv);
872             c->fVerStreamOffset     = 0.5f * (STREAM_MAX_Y - STREAM_MIN_Y) * (0.01f * c->sStateStage.fPV_pVerPos + 1.0f) + STREAM_MIN_Y;
873         }
874 
875         if (c->nUpdate & UPD_TRIGGER)
876         {
877             trg_mode_t trgMode      = get_trigger_mode(c->sStateStage.nPV_pTrgMode);
878 
879             c->bAutoSweep           = !((trgMode == TRG_MODE_SINGLE) || (trgMode == TRG_MODE_MANUAL));
880             c->sTrigger.set_trigger_mode(trgMode);
881             c->sTrigger.set_trigger_hysteresis(0.01f * c->sStateStage.fPV_pTrgHys * STREAM_N_VER_DIV * c->sStateStage.fPV_pVerDiv);
882             c->sTrigger.set_trigger_type(get_trigger_type(c->sStateStage.nPV_pTrgType));
883             c->sTrigger.set_trigger_threshold(0.5f * STREAM_N_VER_DIV * c->sStateStage.fPV_pVerDiv * 0.01f * c->sStateStage.fPV_pTrgLevel);
884             c->sTrigger.update_settings();
885         }
886 
887         if (c->nUpdate & UPD_TRGGER_RESET)
888         {
889             c->sTrigger.reset_single_trigger();
890             c->sTrigger.activate_manual_trigger();
891         }
892 
893         c->bClearStream = true;
894 
895         // Clear the update flag
896         c->nUpdate = 0;
897     }
898 
graph_stream(channel_t * c)899     bool oscilloscope_base::graph_stream(channel_t * c)
900     {
901         // Remember size and reset head
902         size_t query_size   = c->nDisplayHead;
903         c->nDisplayHead     = 0;
904 
905         // Check that stream is present
906         stream_t *stream = c->pStream->getBuffer<stream_t>();
907         if ((stream == NULL) || (c->bFreeze))
908             return false;
909 
910         if (c->bClearStream)
911         {
912             stream->clear();
913             c->bClearStream = false;
914         }
915 
916         // Transform XY -> MS for goniomteter mode
917         if (c->enMode == CH_MODE_GONIOMETER)
918             dsp::lr_to_ms(c->vDisplay_y, c->vDisplay_x, c->vDisplay_y, c->vDisplay_x, query_size);
919 
920         // In-place decimation:
921         size_t j = 0;
922 
923         for (size_t i = 1; i < query_size; ++i)
924         {
925             float dx    = c->vDisplay_x[i] - c->vDisplay_x[j];
926             float dy    = c->vDisplay_y[i] - c->vDisplay_y[j];
927             float s     = dx*dx + dy*dy;
928 
929             if (s < DECIM_PRECISION) // Skip point
930             {
931                 c->vDisplay_s[j] = lsp_max(c->vDisplay_s[i], c->vDisplay_s[j]); // Keep the strobe signal
932                 continue;
933             }
934 
935             // Add point to decimated array
936             ++j;
937             c->vDisplay_x[j] = c->vDisplay_x[i];
938             c->vDisplay_y[j] = c->vDisplay_y[i];
939         }
940 
941         // Detect occasional jumps
942         size_t to_submit = j + 1; // Total number of decimated samples.
943 
944         // Apply scaling and offset:
945         dsp::mul_k2(c->vDisplay_y, c->fVerStreamScale, to_submit);
946         dsp::add_k2(c->vDisplay_y, c->fVerStreamOffset, to_submit);
947 
948         // x is to be scaled and offset only in XY mode
949         if ((c->enMode == CH_MODE_XY) || (c->enMode == CH_MODE_GONIOMETER))
950         {
951             dsp::mul_k2(c->vDisplay_x, c->fHorStreamScale, to_submit);
952             dsp::add_k2(c->vDisplay_x, c->fHorStreamOffset, to_submit);
953         }
954 
955 //    #ifdef LSP_TRACE
956 //        for (size_t i=1; i < to_submit; ++i)
957 //        {
958 //            float dx    = c->vDisplay_x[i] - c->vDisplay_x[i-1];
959 //            float dy    = c->vDisplay_y[i] - c->vDisplay_y[i-1];
960 //            float s     = dx*dx + dy*dy;
961 //            if ((s >= 0.125f) && (c->vDisplay_s[i] <= 0.5f))
962 //            {
963 //                lsp_trace("debug");
964 //            }
965 //        }
966 //    #endif
967 
968         // Submit data for plotting (emit the figure data with fixed-size frames):
969         for (size_t i = 0; i < to_submit; )  // nSweepSize can be as big as BUF_LIM_SIZE !!!
970         {
971             size_t count = stream->add_frame(to_submit - i);     // Add a frame
972             stream->write_frame(0, &c->vDisplay_x[i], 0, count); // X'es
973             stream->write_frame(1, &c->vDisplay_y[i], 0, count); // Y's
974             stream->write_frame(2, &c->vDisplay_s[i], 0, count); // Strobe signal
975             stream->commit_frame();                              // Commit the frame
976 
977             // Move the index in the source buffer
978             i += count;
979         }
980 
981         // Is there data to submit to inline display?
982         if (to_submit > 0)
983         {
984             // Compute the start point to submit data
985             j   = 0;
986 
987             // In-place decimation:
988             for (size_t i = j+1; i < to_submit; ++i)
989             {
990                 float dx    = c->vDisplay_x[i] - c->vDisplay_x[j];
991                 float dy    = c->vDisplay_y[i] - c->vDisplay_y[j];
992                 float s     = dx*dx + dy*dy;
993 
994                 if (s < IDISPLAY_DECIM) // Skip point
995                     continue;
996 
997                 // Add point to decimated array
998                 ++j;
999                 c->vDisplay_x[j] = c->vDisplay_x[i];
1000                 c->vDisplay_y[j] = c->vDisplay_y[i];
1001             }
1002 
1003             // Copy display data to inline display buffer.
1004             c->nIDisplay = j + 1;
1005             dsp::copy(c->vIDisplay_x, c->vDisplay_x, c->nIDisplay);
1006             dsp::copy(c->vIDisplay_y, c->vDisplay_y, c->nIDisplay);
1007         }
1008 
1009         return true;
1010     }
1011 
update_settings()1012     void oscilloscope_base::update_settings()
1013     {
1014         float xy_rectime    = pXYRecordTime->getValue();
1015         bool g_freeze       = pFreeze->getValue() >= 0.5f;
1016         bool has_solo       = false;
1017 
1018         for (size_t ch = 0; ch < nChannels; ++ch)
1019         {
1020             channel_t *c    = &vChannels[ch];
1021             bool solo       = (c->pSoloSwitch != NULL) ? c->pSoloSwitch->getValue() >= 0.5f : false;
1022             if (solo)
1023                 has_solo        = true;
1024         }
1025 
1026         for (size_t ch = 0; ch < nChannels; ++ch)
1027         {
1028             channel_t *c = &vChannels[ch];
1029 
1030             // Global controls only actually exist for mult-channel plugins. Do not use for 1X.
1031             if (nChannels > 1)
1032                 c->bUseGlobal = c->pGlobalSwitch->getValue() >= 0.5f;
1033 
1034             bool solo       = (c->pSoloSwitch != NULL) ? c->pSoloSwitch->getValue() >= 0.5f : false;
1035             bool mute       = (c->pMuteSwitch != NULL) ? c->pMuteSwitch->getValue() >= 0.5f : false;
1036             c->bVisible     = (has_solo) ? solo : !mute;
1037 
1038             c->bFreeze      = g_freeze;
1039             if ((!c->bFreeze) && (nChannels > 1))
1040                 c->bFreeze      = c->pFreezeSwitch->getValue() >= 0.5f;
1041 
1042             if (xy_rectime != c->sStateStage.fPV_pXYRecordTime)
1043             {
1044                 c->sStateStage.fPV_pXYRecordTime = xy_rectime;
1045                 c->nUpdate |= UPD_XY_RECORD_TIME;
1046             }
1047 
1048             size_t scpmode = (c->bUseGlobal) ? pScpMode->getValue() : c->pScpMode->getValue();
1049             if (scpmode != c->sStateStage.nPV_pScpMode)
1050             {
1051                 c->sStateStage.nPV_pScpMode = scpmode;
1052                 c->nUpdate |= UPD_SCPMODE;
1053             }
1054 
1055             size_t coupling_x = (c->bUseGlobal) ? pCoupling_x->getValue() : c->pCoupling_x->getValue();
1056             if (coupling_x != c->sStateStage.nPV_pCoupling_x)
1057             {
1058                 c->sStateStage.nPV_pCoupling_x = coupling_x;
1059                 c->nUpdate |= UPD_ACBLOCK_X;
1060             }
1061 
1062             size_t coupling_y = (c->bUseGlobal) ? pCoupling_y->getValue() : c->pCoupling_y->getValue();
1063             if (coupling_y != c->sStateStage.nPV_pCoupling_y)
1064             {
1065                 c->sStateStage.nPV_pCoupling_y = coupling_y;
1066                 c->nUpdate |= UPD_ACBLOCK_Y;
1067             }
1068 
1069             size_t coupling_ext = (c->bUseGlobal) ? pCoupling_ext->getValue() : c->pCoupling_ext->getValue();
1070             if (coupling_ext != c->sStateStage.nPV_pCoupling_ext)
1071             {
1072                 c->sStateStage.nPV_pCoupling_ext = coupling_ext;
1073                 c->nUpdate |= UPD_ACBLOCK_EXT;
1074             }
1075 
1076             size_t overmode = (c->bUseGlobal) ? pOvsMode->getValue() : c->pOvsMode->getValue();
1077             if (overmode != c->sStateStage.nPV_pOvsMode)
1078             {
1079                 c->sStateStage.nPV_pOvsMode = overmode;
1080                 c->nUpdate |= UPD_OVERSAMPLER_X | UPD_OVERSAMPLER_Y | UPD_OVERSAMPLER_EXT |
1081                               UPD_PRETRG_DELAY | UPD_SWEEP_GENERATOR | UPD_TRIGGER_HOLD |
1082                               UPD_XY_RECORD_TIME | UPD_SWEEP_GENERATOR;
1083             }
1084 
1085             size_t trginput = (c->bUseGlobal) ? pTrgInput->getValue() : c->pTrgInput->getValue();
1086             if (trginput != c->sStateStage.nPV_pTrgInput)
1087             {
1088                 c->sStateStage.nPV_pTrgInput = trginput;
1089                 c->nUpdate |= UPD_TRIGGER_INPUT;
1090             }
1091 
1092             float verDiv = (c->bUseGlobal) ? pVerDiv->getValue() : c->pVerDiv->getValue();
1093             float verPos = (c->bUseGlobal) ? pVerPos->getValue() : c->pVerPos->getValue();
1094             if ((verDiv != c->sStateStage.fPV_pVerDiv) || (verPos != c->sStateStage.fPV_pVerPos))
1095             {
1096                 c->sStateStage.fPV_pVerDiv = verDiv;
1097                 c->sStateStage.fPV_pVerPos = verPos;
1098                 c->nUpdate |= UPD_VER_SCALES | UPD_TRIGGER;
1099             }
1100 
1101             float trgHys = (c->bUseGlobal) ? pTrgHys->getValue() : c->pTrgHys->getValue();
1102             if (trgHys != c->sStateStage.fPV_pTrgHys)
1103             {
1104                 c->sStateStage.fPV_pTrgHys = trgHys;
1105                 c->nUpdate |= UPD_TRIGGER;
1106             }
1107 
1108             float trgLevel = (c->bUseGlobal) ? pTrgLev->getValue() : c->pTrgLev->getValue();
1109             if (trgLevel != c->sStateStage.fPV_pTrgLevel)
1110             {
1111                 c->sStateStage.fPV_pTrgLevel = trgLevel;
1112                 c->nUpdate |= UPD_TRIGGER;
1113             }
1114 
1115             size_t trgmode = (c->bUseGlobal) ? pTrgMode->getValue() : c->pTrgMode->getValue();
1116             if (trgmode != c->sStateStage.nPV_pTrgMode)
1117             {
1118                 c->sStateStage.nPV_pTrgMode = trgmode;
1119                 c->nUpdate |= UPD_TRIGGER;
1120             }
1121 
1122             float trghold = (c->bUseGlobal) ? pTrgHold->getValue() : c->pTrgHold->getValue();
1123             if (trghold != c->sStateStage.fPV_pTrgHold)
1124             {
1125                 c->sStateStage.fPV_pTrgHold = trghold;
1126                 c->nUpdate |= UPD_TRIGGER_HOLD;
1127             }
1128 
1129             size_t trgtype = (c->bUseGlobal) ? pTrgType->getValue() : c->pTrgType->getValue();
1130             if (trgtype != c->sStateStage.nPV_pTrgType)
1131             {
1132                 c->sStateStage.nPV_pTrgType = trgtype;
1133                 c->nUpdate |= UPD_TRIGGER;
1134             }
1135 
1136             float trg_reset = (c->bUseGlobal) ? pTrgReset->getValue() : c->pTrgReset->getValue();
1137             if (trg_reset >= 0.5f)
1138                 c->nUpdate |= UPD_TRGGER_RESET;
1139 
1140             float timeDiv = (c->bUseGlobal) ? pTimeDiv->getValue() : c->pTimeDiv->getValue();
1141             if (timeDiv != c->sStateStage.fPV_pTimeDiv)
1142             {
1143                 c->sStateStage.fPV_pTimeDiv = timeDiv;
1144                 c->nUpdate |= UPD_PRETRG_DELAY | UPD_SWEEP_GENERATOR | UPD_TRIGGER_HOLD;
1145             }
1146 
1147             float horDiv = (c->bUseGlobal) ? pHorDiv->getValue() : c->pHorDiv->getValue();
1148             if (timeDiv != c->sStateStage.fPV_pHorDiv)
1149             {
1150                 c->sStateStage.fPV_pHorDiv = horDiv;
1151                 c->nUpdate |= UPD_HOR_SCALES;
1152             }
1153 
1154             float horPos = (c->bUseGlobal) ? pHorPos->getValue() : c->pHorPos->getValue();
1155             if (horPos != c->sStateStage.fPV_pHorPos)
1156             {
1157                 c->sStateStage.fPV_pHorPos = horPos;
1158                 c->nUpdate |= UPD_HOR_SCALES | UPD_PRETRG_DELAY | UPD_SWEEP_GENERATOR;
1159             }
1160 
1161             size_t sweeptype = (c->bUseGlobal) ? pSweepType->getValue() : c->pSweepType->getValue();
1162             if (sweeptype != c->sStateStage.nPV_pSweepType)
1163             {
1164                 c->sStateStage.nPV_pSweepType = sweeptype;
1165                 c->nUpdate |= UPD_SWEEP_GENERATOR;
1166             }
1167         }
1168     }
1169 
update_sample_rate(long sr)1170     void oscilloscope_base::update_sample_rate(long sr)
1171     {
1172         reconfigure_dc_block_filters();
1173 
1174         for (size_t ch = 0; ch < nChannels; ++ch)
1175         {
1176             channel_t *c = &vChannels[ch];
1177 
1178             c->sOversampler_x.set_sample_rate(sr);
1179             c->sOversampler_x.update_settings();
1180 
1181             c->sOversampler_y.set_sample_rate(sr);
1182             c->sOversampler_y.update_settings();
1183 
1184             c->sOversampler_ext.set_sample_rate(sr);
1185             c->sOversampler_ext.update_settings();
1186 
1187             c->nOverSampleRate = c->nOversampling * sr;
1188 
1189             c->sSweepGenerator.set_sample_rate(sr);
1190             c->sSweepGenerator.update_settings();
1191         }
1192     }
1193 
process(size_t samples)1194     void oscilloscope_base::process(size_t samples)
1195     {
1196         // Prepare channels
1197         for (size_t ch = 0; ch < nChannels; ++ch)
1198         {
1199             channel_t *c = &vChannels[ch];
1200 
1201             c->vIn_x    = c->pIn_x->getBuffer<float>();
1202             c->vIn_y    = c->pIn_y->getBuffer<float>();
1203             c->vIn_ext  = c->pIn_ext->getBuffer<float>();
1204 
1205             c->vOut_x   = c->pOut_x->getBuffer<float>();
1206             c->vOut_y   = c->pOut_y->getBuffer<float>();
1207 
1208             if ((c->vIn_x == NULL) || (c->vIn_y == NULL))
1209                 return;
1210 
1211             if ((c->vIn_ext == NULL))
1212                 return;
1213 
1214             c->nSamplesCounter = samples;
1215         }
1216 
1217         // Bypass signal
1218         for (size_t ch = 0; ch < nChannels; ++ch)
1219         {
1220             channel_t *c = &vChannels[ch];
1221 
1222             if (c->vOut_x != NULL)
1223                 dsp::copy(c->vOut_x, c->vIn_x, samples);
1224             if (c->vOut_y != NULL)
1225                 dsp::copy(c->vOut_y, c->vIn_y, samples);
1226         }
1227 
1228         bool query_draw = false;
1229 
1230         // Process each channel
1231         for (size_t ch = 0; ch < nChannels; ++ch)
1232         {
1233             channel_t *c = &vChannels[ch];
1234 
1235             commit_staged_state_change(c);
1236 
1237             while (c->nSamplesCounter > 0)
1238             {
1239                 size_t requested        = c->nOversampling * c->nSamplesCounter;
1240                 size_t availble         = BUF_LIM_SIZE;
1241                 size_t to_do_upsample   = (requested < availble) ? requested : availble;
1242                 size_t to_do            = to_do_upsample / c->nOversampling;
1243 
1244                 switch (c->enMode)
1245                 {
1246                     case CH_MODE_XY:
1247                     case CH_MODE_GONIOMETER:
1248                     {
1249                         if (c->enCoupling_x == CH_COUPLING_AC)
1250                         {
1251                             c->sDCBlockBank_x.process(c->vTemp, c->vIn_x, to_do);
1252                             c->sOversampler_x.upsample(c->vData_x, c->vTemp, to_do);
1253                         }
1254                         else
1255                             c->sOversampler_x.upsample(c->vData_x, c->vIn_x, to_do);
1256 
1257                         if (c->enCoupling_y == CH_COUPLING_AC)
1258                         {
1259                             c->sDCBlockBank_y.process(c->vTemp, c->vIn_y, to_do);
1260                             c->sOversampler_y.upsample(c->vData_y, c->vTemp, to_do);
1261                         }
1262                         else
1263                             c->sOversampler_y.upsample(c->vData_y, c->vIn_y, to_do);
1264 
1265                         for (size_t n = 0; n < to_do_upsample; )
1266                         {
1267                             ssize_t count = lsp_min(ssize_t(c->nXYRecordSize - c->nDisplayHead), ssize_t(to_do_upsample - n));
1268                             if (count <= 0)
1269                             {
1270                                 // Plot time!
1271                                 if (graph_stream(c))
1272                                     query_draw      = true;
1273                                 continue;
1274                             }
1275 
1276                             // Move data to intermediate buffers
1277                             dsp::copy(&c->vDisplay_x[c->nDisplayHead], &c->vData_x[n], count);
1278                             dsp::copy(&c->vDisplay_y[c->nDisplayHead], &c->vData_y[n], count);
1279                             dsp::fill_zero(&c->vDisplay_s[c->nDisplayHead], count);
1280                             if (c->nDisplayHead == 0)
1281                                 c->vDisplay_s[0]        = 1.0f;
1282 
1283                             // Update pointers
1284                             c->nDisplayHead    += count;
1285                             n                  += count;
1286                         }
1287 
1288                     }
1289                     break;
1290 
1291                     case CH_MODE_TRIGGERED:
1292                     {
1293                         if (c->enCoupling_y == CH_COUPLING_AC)
1294                         {
1295                             c->sDCBlockBank_y.process(c->vTemp, c->vIn_y, to_do);
1296                             c->sOversampler_y.upsample(c->vData_y, c->vTemp, to_do);
1297                         }
1298                         else
1299                             c->sOversampler_y.upsample(c->vData_y, c->vIn_y, to_do);
1300 
1301                         c->sPreTrgDelay.process(c->vData_y_delay, c->vData_y, to_do_upsample);
1302 
1303                         if (c->enCoupling_ext == CH_COUPLING_AC)
1304                         {
1305                             c->sDCBlockBank_ext.process(c->vTemp, c->vIn_ext, to_do);
1306                             c->sOversampler_ext.upsample(c->vData_ext, c->vTemp, to_do);
1307                         }
1308                         else
1309                             c->sOversampler_ext.upsample(c->vData_ext, c->vIn_ext, to_do);
1310 
1311                         c->nDataHead = 0;
1312 
1313                         const float *trg_input = select_trigger_input(c->vData_ext, c->vData_y, c->enTrgInput);
1314 
1315                         for (size_t n = 0; n < to_do_upsample; ++n)
1316                         {
1317                             c->sTrigger.single_sample_processor(trg_input[n]);
1318 
1319                             switch (c->enState)
1320                             {
1321                                 case CH_STATE_LISTENING:
1322                                 {
1323                                     bool sweep = c->sTrigger.get_trigger_state() == TRG_STATE_FIRED;
1324                                     if ((!sweep) && (c->bAutoSweep))
1325                                         sweep = ((c->nAutoSweepCounter++) >= c->nAutoSweepLimit);
1326 
1327                                     // No sweep triggered?
1328                                     if (!sweep)
1329                                         break;
1330 
1331                                     c->sSweepGenerator.reset_phase_accumulator();
1332                                     c->nDataHead            = n;
1333                                     c->enState              = CH_STATE_SWEEPING;
1334                                     c->nAutoSweepCounter    = 0;
1335                                     c->nDisplayHead         = 0;
1336 
1337                                     do_sweep_step(c, 1.0f);
1338 
1339                                     break;
1340                                 }
1341 
1342                                 case CH_STATE_SWEEPING:
1343                                     do_sweep_step(c, 0.0f);
1344 
1345                                     if (c->nDisplayHead >= c->nSweepSize)
1346                                     {
1347                                         // Plot time!
1348                                         if (graph_stream(c))
1349                                             query_draw      = true;
1350                                         c->enState      = CH_STATE_LISTENING;
1351                                     }
1352                                     break;
1353                             }
1354                         }
1355                     }
1356                     break;
1357                 }
1358 
1359                 c->vIn_x            += to_do;
1360                 c->vIn_y            += to_do;
1361                 c->vIn_ext          += to_do;
1362                 c->vOut_x           += to_do;
1363                 c->vOut_y           += to_do;
1364                 c->nSamplesCounter  -= to_do;
1365             }
1366         }
1367 
1368         if ((pWrapper != NULL) && (query_draw))
1369             pWrapper->query_display_draw();
1370     }
1371 
dump(IStateDumper * v) const1372     void oscilloscope_base::dump(IStateDumper *v) const
1373     {
1374         plugin_t::dump(v);
1375 
1376         v->begin_object("sDCBlockParams", &sDCBlockParams, sizeof(sDCBlockParams));
1377         {
1378             v->write("fAlpha", sDCBlockParams.fAlpha);
1379             v->write("fGain", sDCBlockParams.fGain);
1380         }
1381         v->end_object();
1382 
1383         v->write("nChannels", nChannels);
1384 
1385         v->begin_array("vChannels", vChannels, nChannels);
1386         for (size_t i = 0; i < nChannels; ++i)
1387         {
1388             const channel_t *c = &vChannels[i];
1389 
1390             v->begin_object(c, sizeof(channel_t));
1391             {
1392                 v->write("enMode", &c->enMode);
1393                 v->write("enSweepType", &c->enSweepType);
1394                 v->write("enTrgInput", &c->enTrgInput);
1395                 v->write("enCoupling_x", &c->enCoupling_x);
1396                 v->write("enCoupling_y", &c->enCoupling_y);
1397                 v->write("enCoupling_ext", &c->enCoupling_ext);
1398 
1399                 v->write_object("sDCBlockBank_x", &c->sDCBlockBank_x);
1400                 v->write_object("sDCBlockBank_y", &c->sDCBlockBank_y);
1401                 v->write_object("sDCBlockBank_ext", &c->sDCBlockBank_ext);
1402 
1403                 v->write("enOverMode", &c->enOverMode);
1404                 v->write("nOversampling", &c->nOversampling);
1405                 v->write("nOverSampleRate", &c->nOverSampleRate);
1406 
1407                 v->write_object("sOversampler_x", &c->sOversampler_x);
1408                 v->write_object("sOversampler_y", &c->sOversampler_y);
1409                 v->write_object("sOversampler_ext", &c->sOversampler_ext);
1410 
1411                 v->write_object("sPreTrgDelay", &c->sPreTrgDelay);
1412 
1413                 v->write_object("sTrigger", &c->sTrigger);
1414 
1415                 v->write_object("sSweepGenerator", &c->sSweepGenerator);
1416 
1417                 v->write("vTemp", &c->vTemp);
1418                 v->write("vData_x", &c->vData_x);
1419                 v->write("vData_y", &c->vData_y);
1420                 v->write("vData_ext", &c->vData_ext);
1421                 v->write("vData_y_delay", &c->vData_y_delay);
1422                 v->write("vDisplay_x", &c->vDisplay_x);
1423                 v->write("vDisplay_y", &c->vDisplay_y);
1424                 v->write("vDisplay_s", &c->vDisplay_s);
1425 
1426                 v->write("vIDisplay_x", &c->vIDisplay_x);
1427                 v->write("vIDisplay_y", &c->vIDisplay_y);
1428                 v->write("nIDisplay", &c->nIDisplay);
1429 
1430                 v->write("nDataHead", &c->nDataHead);
1431                 v->write("nDisplayHead", &c->nDisplayHead);
1432                 v->write("nSamplesCounter", &c->nSamplesCounter);
1433                 v->write("bClearStream", &c->bClearStream);
1434 
1435                 v->write("nPreTrigger", &c->nPreTrigger);
1436                 v->write("nSweepSize", &c->nSweepSize);
1437 
1438                 v->write("fVerStreamScale", &c->fVerStreamScale);
1439                 v->write("fVerStreamOffset", &c->fVerStreamOffset);
1440 
1441                 v->write("nXYRecordSize", &c->nXYRecordSize);
1442                 v->write("fHorStreamScale", &c->fHorStreamScale);
1443                 v->write("fHorStreamOffset", &c->fHorStreamOffset);
1444 
1445                 v->write("bAutoSweep", &c->bAutoSweep);
1446                 v->write("nAutoSweepLimit", &c->nAutoSweepLimit);
1447                 v->write("nAutoSweepCounter", &c->nAutoSweepCounter);
1448 
1449                 v->write("enState", &c->enState);
1450 
1451                 v->write("nUpdate", &c->nUpdate);
1452 
1453                 v->begin_object("sStateStage", &c->sStateStage, sizeof(c->sStateStage));
1454                 {
1455                     v->write("nPV_pScpMode", &c->sStateStage.nPV_pScpMode);
1456 
1457                     v->write("nPV_pCoupling_x", &c->sStateStage.nPV_pCoupling_x);
1458                     v->write("nPV_pCoupling_y", &c->sStateStage.nPV_pCoupling_y);
1459                     v->write("nPV_pCoupling_ext", &c->sStateStage.nPV_pCoupling_ext);
1460                     v->write("nPV_pOvsMode", &c->sStateStage.nPV_pOvsMode);
1461 
1462                     v->write("nPV_pTrgInput", &c->sStateStage.nPV_pTrgInput);
1463                     v->write("fPV_pVerDiv", &c->sStateStage.fPV_pVerDiv);
1464                     v->write("fPV_pVerPos", &c->sStateStage.fPV_pVerPos);
1465                     v->write("fPV_pTrgLevel", &c->sStateStage.fPV_pTrgLevel);
1466                     v->write("fPV_pTrgHys", &c->sStateStage.fPV_pTrgHys);
1467                     v->write("nPV_pTrgMode", &c->sStateStage.nPV_pTrgMode);
1468                     v->write("fPV_pTrgHold", &c->sStateStage.fPV_pTrgHold);
1469                     v->write("nPV_pTrgType", &c->sStateStage.nPV_pTrgType);
1470 
1471                     v->write("fPV_pTimeDiv", &c->sStateStage.fPV_pTimeDiv);
1472                     v->write("fPV_pHorPos", &c->sStateStage.fPV_pHorPos);
1473 
1474                     v->write("nPV_pSweepType", &c->sStateStage.nPV_pSweepType);
1475 
1476                     v->write("fPV_pXYRecordTime", &c->sStateStage.fPV_pXYRecordTime);
1477                 }
1478                 v->end_object();
1479 
1480                 v->write("bUseGlobal", &c->bUseGlobal);
1481                 v->write("bFreeze", &c->bFreeze);
1482 
1483                 v->write("vIn_x", &c->vIn_x);
1484                 v->write("vIn_y", &c->vIn_y);
1485                 v->write("vIn_ext", &c->vIn_ext);
1486 
1487                 v->write("vOut_x", &c->vOut_x);
1488                 v->write("vOut_y", &c->vOut_y);
1489 
1490                 v->write("pIn_x", &c->pIn_x);
1491                 v->write("pIn_y", &c->pIn_y);
1492                 v->write("pIn_ext", &c->pIn_ext);
1493 
1494                 v->write("pOut_x", &c->pOut_x);
1495                 v->write("pOut_y", &c->pOut_y);
1496 
1497                 v->write("pOvsMode", &c->pOvsMode);
1498                 v->write("pScpMode", &c->pScpMode);
1499                 v->write("pCoupling_x", &c->pCoupling_x);
1500                 v->write("pCoupling_y", &c->pCoupling_y);
1501                 v->write("pCoupling_ext", &c->pCoupling_ext);
1502 
1503                 v->write("pSweepType", &c->pSweepType);
1504                 v->write("pTimeDiv", &c->pTimeDiv);
1505                 v->write("pHorDiv", &c->pHorDiv);
1506                 v->write("pHorPos", &c->pHorPos);
1507 
1508                 v->write("pVerDiv", &c->pVerDiv);
1509                 v->write("pVerPos", &c->pVerPos);
1510 
1511                 v->write("pTrgHys", &c->pTrgHys);
1512                 v->write("pTrgLev", &c->pTrgLev);
1513                 v->write("pTrgHold", &c->pTrgHold);
1514                 v->write("pTrgMode", &c->pTrgMode);
1515                 v->write("pTrgType", &c->pTrgType);
1516                 v->write("pTrgInput", &c->pTrgInput);
1517                 v->write("pTrgReset", &c->pTrgReset);
1518 
1519                 v->write("pGlobalSwitch", &c->pGlobalSwitch);
1520                 v->write("pFreezeSwitch", &c->pFreezeSwitch);
1521                 v->write("pSoloSwitch", &c->pSoloSwitch);
1522                 v->write("pMuteSwitch", &c->pMuteSwitch);
1523 
1524                 v->write("pStream", &c->pStream);
1525             }
1526             v->end_object();
1527         }
1528         v->end_array();
1529 
1530         v->write("pData", pData);
1531 
1532         v->write("pStrobeHistSize", pStrobeHistSize);
1533         v->write("pXYRecordTime", pXYRecordTime);
1534         v->write("pFreeze", pFreeze);
1535 
1536         v->write("pChannelSelector", pChannelSelector);
1537 
1538         v->write("pOvsMode", pOvsMode);
1539         v->write("pScpMode", pScpMode);
1540         v->write("pCoupling_x", pCoupling_x);
1541         v->write("pCoupling_y", pCoupling_y);
1542         v->write("pCoupling_ext", pCoupling_ext);
1543 
1544         v->write("pSweepType", pSweepType);
1545         v->write("pTimeDiv", pTimeDiv);
1546         v->write("pHorDiv", pHorDiv);
1547         v->write("pHorPos", pHorPos);
1548 
1549         v->write("pVerDiv", pVerDiv);
1550         v->write("pVerPos", pVerPos);
1551 
1552         v->write("pTrgHys", pTrgHys);
1553         v->write("pTrgLev", pTrgLev);
1554         v->write("pTrgHold", pTrgHold);
1555         v->write("pTrgMode", pTrgMode);
1556         v->write("pTrgType", pTrgType);
1557         v->write("pTrgInput", pTrgInput);
1558         v->write("pTrgReset", pTrgReset);
1559 
1560         v->write("pIDisplay", pIDisplay);
1561     }
1562 
1563     static const uint32_t ch_colors[] =
1564     {
1565         // x1
1566         0x0a9bff,
1567         // x2
1568         0xff0e11,
1569         0x0a9bff,
1570         // x4
1571         0xff0e11,
1572         0x12ff16,
1573         0xff6c11,
1574         0x0a9bff
1575     };
1576 
inline_display(ICanvas * cv,size_t width,size_t height)1577     bool oscilloscope_base::inline_display(ICanvas *cv, size_t width, size_t height)
1578     {
1579         // Check proportions
1580         if (height > width)
1581             height  = width;
1582 
1583         // Init canvas
1584         if (!cv->init(width, height))
1585             return false;
1586         width   = cv->width();
1587         height  = cv->height();
1588         float cx    = width >> 1;
1589         float cy    = height >> 1;
1590 
1591         // Clear background
1592         cv->paint();
1593 
1594         // Draw axis
1595         cv->set_line_width(1.0);
1596         cv->set_color_rgb(CV_SILVER, 0.5f);
1597         cv->line(0, 0, width, height);
1598         cv->line(0, height, width, 0);
1599 
1600         cv->set_color_rgb(CV_WHITE, 0.5f);
1601         cv->line(cx, 0, cx, height);
1602         cv->line(0, cy, width, cy);
1603 
1604         // Check for solos:
1605         const uint32_t *cols =
1606                 (nChannels < 2) ? &ch_colors[0] :
1607                 (nChannels < 4) ? &ch_colors[1] :
1608                 &ch_colors[3];
1609 
1610         float halfv = 0.5f * width;
1611         float halfh = 0.5f * height;
1612 
1613         // Estimate the display length
1614         size_t di_length = 1;
1615         for (size_t ch = 0; ch < nChannels; ++ch)
1616             di_length = lsp_max(di_length, vChannels[ch].nIDisplay);
1617 
1618         // Allocate buffer: t, f(t)
1619         pIDisplay = float_buffer_t::reuse(pIDisplay, 2, di_length);
1620         float_buffer_t *b = pIDisplay;
1621         if (b == NULL)
1622             return false;
1623 
1624         bool aa = cv->set_anti_aliasing(true);
1625 
1626         for (size_t ch = 0; ch < nChannels; ++ch)
1627         {
1628             channel_t *c = &vChannels[ch];
1629             if (!c->bVisible)
1630                 continue;
1631 
1632             size_t dlen = lsp_min(c->nIDisplay, di_length);
1633             for (size_t i=0; i<dlen; ++i)
1634             {
1635                 b->v[0][i] = halfv * (c->vIDisplay_x[i] + 1.0f);
1636                 b->v[1][i] = halfh * (-c->vIDisplay_y[i] + 1.0f);
1637             }
1638 
1639             // Set color and draw
1640             cv->set_color_rgb(cols[ch]);
1641             cv->set_line_width(2);
1642             cv->draw_lines(b->v[0], b->v[1], dlen);
1643         }
1644 
1645         cv->set_anti_aliasing(aa);
1646 
1647         return true;
1648     }
1649 
oscilloscope_x1()1650     oscilloscope_x1::oscilloscope_x1(): oscilloscope_base(metadata, 1)
1651     {
1652     }
1653 
~oscilloscope_x1()1654     oscilloscope_x1::~oscilloscope_x1()
1655     {
1656     }
1657 
oscilloscope_x2()1658     oscilloscope_x2::oscilloscope_x2(): oscilloscope_base(metadata, 2)
1659     {
1660     }
1661 
~oscilloscope_x2()1662     oscilloscope_x2::~oscilloscope_x2()
1663     {
1664     }
1665 
oscilloscope_x4()1666     oscilloscope_x4::oscilloscope_x4(): oscilloscope_base(metadata, 4)
1667     {
1668     }
1669 
~oscilloscope_x4()1670     oscilloscope_x4::~oscilloscope_x4()
1671     {
1672     }
1673 }
1674