HISE Logo Forum
    • Categories
    • Register
    • Login

    How to draw super smooth Waveform?

    Scheduled Pinned Locked Moved General Questions
    13 Posts 6 Posters 813 Views
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • d.healeyD
      d.healey @oskarsh
      last edited by

      @oskarsh Posting a snippet might help.

      Libre Wave - Freedom respecting instruments and effects
      My Patreon - HISE tutorials
      YouTube Channel - Public HISE tutorials

      Christoph HartC 1 Reply Last reply Reply Quote 0
      • Christoph HartC
        Christoph Hart @d.healey
        last edited by

        There's a dubious function available as LAF callback that lets you customize the audio rendering options:

        
        const var AudioWaveform1 = Content.getComponent("AudioWaveform1");
        
        const var laf = Content.createLocalLookAndFeel();
        
        laf.registerFunction("getThumbnailRenderOptions", function(obj)
        {
        	 Console.print(trace(obj));
        	 
        	 obj.manualDownSampleFactor = 4.0;
        	 return obj;
        	 
        });
        
        AudioWaveform1.setLocalLookAndFeel(laf);
        

        By changing the manualDownSampleFactor property you can get a low-res signal with less edges which you can then make more rounded using the function you mentioned above.

        mmprodM 1 Reply Last reply Reply Quote 5
        • mmprodM
          mmprod @Christoph Hart
          last edited by

          @Christoph-Hart Can I do this to the oscilloscope per chance? Or get a similar effect

          For God so loved the world that he gave his one and only Son, that whoever believes in him shall not perish but have eternal life.
          John 3:16

          oskarshO M HISEnbergH 3 Replies Last reply Reply Quote 0
          • oskarshO
            oskarsh @mmprod
            last edited by

            @mmprod Yes you will need to use a scriptnode oscilloscope buffer. Instead of downsampling inside the LAF you will need to downsample the audio signal in the scriptnode network. You can then smooth the path the same.

            mmprodM 1 Reply Last reply Reply Quote 1
            • M
              Mighty23 @mmprod
              last edited by

              @mmprod
              https://forum.hise.audio/topic/11419/help-needed-detecting-audio-signal-in-display-buffer-for-oscilloscope-animation

              If this is something you've never done before, this post could be a great starting point. It’s not exactly what you’re looking for, but it’s a good foundation for customizing your own oscilloscope using the one in Scriptnode.

              Free Party, Free Tekno & Free Software too

              1 Reply Last reply Reply Quote 1
              • HISEnbergH
                HISEnberg @mmprod
                last edited by

                @mmprod I am still not done this but I am working on an oscilloscope I plan to share soon with interpolation to smooth the waveform:

                HiseSnippet 3945.3oc6Zz1Tabb9D3KoVIoMoMMoebKSSFgMHj.AFhKMHCRFl.HUIY6zZ6g43tURq4zcWu6DfZGOS+X+V+KzeJ4mP+MjeA4a8isOO6d6c6JIvDhMYbmnwCV6tOO6979K6plg91znH+Pib46LJfZj68MaOxKt+18sXdF6siQtOxrQjMy00Ox1OftZwJFOXTfUTD0wHWtYeHBVtaeKC9mu6KefkqkmMMaJCiG6yro6yFvhyls4VeErk0sbncXCTftxV6Y66ssuq+Pfjl0rjQfk8IV8nGZgfMiowtVQ8MxcGy0r2X0RGSKs5pqWYk0qTYsJqsZotkVo6wquVkiW4dUVwoxpksWwH26TygE6G1N1JlFYj6VOv2YT699m4INfGyhXG6RwAkMZCmrX559tNHKhyZrcelqSSorJxvH261LSxMqPx8wlGvbXoymIA+P9BjLLTEf4lQm7lUi7JqRdkTHuoPR4THoaIHoOxrscHKHNaEjddOy87hogcs.8jJoHf0Xl+ymXtsO.gWbwAVmPqGBCRwnPkRkVf.+Y96mO+R2gr4qkO4m1jjFs2du82G9ail0H6rW6l6W8OQdvipWuVKx2qc5574NKA72RjGaExr.EPTdvvLJlbpUHIvy8HvonLYShTP0iFus+f.eOXPg4j.LGHjVZoLDqeNhC2ACwnV2tTa.bXZDRU3lNXywE5KQdvPXpPzhJfFFyzHNo7IC+cXQAtViDH0F7r.sXxlog1QfjFoOwNLAlEJMAB6W6vG1YW.kxkVtx8I.k0h5Lzl5PNVPgtTudw8Ic8CIQwVGybYwiFaOZ1Bzts5rWs1v972xSfOyINv84HO2WnbTKHV+vgC.2KOOpaDrb47uDDKRFnXDMtEyqmXOxDQEzOLfWTwnpcL6TZg3vgz44LBeBvkjD2mlvM4Un7N0Nn4QohZwYUzNjBXTHibEaUGJXXDZENRJUPwQfvkDHz74Co837X68d3gU2G1utVtQTNt64whYVtr+JkXEIlOOd9Q1vjd8paYCwNPEPwRb32Yjm0.lsbc.CD.EBu81U2u1Q6TaavUZSRoharNGu1C78i6mgAmFcz2LtoGOPPfuqULy2iTe7seuC6TqUyF6WsydMN7n5U2tSCT.spf5.81w.+62kD3y7hiHw9DV5FBxYZ7YTpGIxZP.5xwc.YQCsbmts9AU+5id3tMZ2AscVcrinWee.r3PKlqJNa2X+FOp0QO3gbuWLQSTwicgrL2eRfZU8IJPERcD13VmQNy5TJHhFPrgECmDy1GznA2yPhbuPfwTD0fOxqbOp14Qsp1o1NJayHJjI9L99fSIzSQVwCCA4mCIfZchJy1tSqFeUsidxd6zYWz0d4DyjIoAP4aehGXQdAXurhQ1CyjrSEuF0q2tVmi3lZ7fCI38XTAB1Rf1oK3ywsqnbN3BzUBoHP.GtSim.tG+Y91s5XVrmw7b7OiDgNI3lY4EyVDrXs3dWJ6lPdhFlc1sUs161X+c39.BWfN8CoQ8gz9pxTvHmaEtM20lzzJtuJABEEgSojHPDC.mrfV3xPqytLHQBfuNd1gJFXJaAWHwo.XWd5ygXdHvEXHObeBi76U7Gfw28tySxKBnlgYwfgQ8KLMR.n1WlmGaoaHTr019C8h46Lm+qhxzpIxTRclK3zRpOzylKg3QjjlTBZi4AgL.8QBHIKmjIQDGbgDMWaPwkRpiyRBPKJRjH4JDPA33GWezlJZ3.A4pOscFeHWfeDu.lawC.NuXWWe+vBYjBYIxxfB4Eje+ljKEfTRQmbvOrtjB.WbWxKlm7GfCm74eNQNdLdRYOlbevOHic2MSP5o7M442eBn374cuq9BuL+jeSpmdJ64fH.27kDHKPU.XHEr98RgkaZ.VA6CpTLHudN.oUv3pbkH6sEAzSU7hjLoJcgpRAdoUzqzhfrHo7zsJT2MgUuTB974mhsPYtFOgvtbkqfZQipW.xtDLzU+W7YStCoPYfpimGTjJ5zx3Jwh.AIhYlpXdLMo3uW34LgLRxyIJVUDkJ2ES+.Qh..Hs7GFiJzrExKKrEKYhCTBLEjJ8B8xB5TrKziWUW2BoobwxWktG+1rJdlP2InRQAPcId9Pr8ddVtKPrN0m4PFBU9gEOgkT4.AKwv7BgB++vnQmwb3AagLDQXkrOAGWHQHf.zmx50OVAhc4SnBx.lCViTBjfSeB0iIe5y5Fmj0JfmSPyRUotDg8I4OvsdWbwIX0rPyBGR0wbE28UYsj7MEscACDIsljZIaRIUtsePZMmNVwVPlQmDeZBKlCUZMvPy8iZQsbRhPqTeqhDQFOHo+iM0ipqfyBSI0sx9nZ9ktWSIbg94svTqtTkesbsGxKjzY5kAKOerLo8omRcgiUgpQyflvRsr75QK.s4pTI+SkZhwq7lmhXf04EJUr7BIiXdEzA6Np0cu.oLXMkRCyqvA6fo9wNNzJAHU7yEK5z7SK8bcq.nOqv3Com0d3w7D6.avMjWTh9cDiuiNmHIhTa3xhnsYhfoGlEoKraU.mkTkWv9y8AyBLNUpmojJC2pQv5WExMCKIei4d53W37EHilWymQUrpkhQS9lRcSZalJhkdeulEwSdhWZ4NZR7KD2KSALEV7GtdPJbtP8fRjsRXjtDDFy3WsS.fAfHUmp20vqLR6lWTnVdA6AV1r3Q7x9WUlKFEjYaz75RB4w2Pzyxl5c2bGjLVTkL3EGlEdGyTJZdqfrGNjqp5Fz2pfVyhKHIt40v2Iw.ufVlhEHOEr5zosEDJ7ERxXAv72lqir8r49B814d4E6jLQrGMlHsy3jMPgBS9eAsU5UQNfB3kSKzWZiDWry5THHgLbRZJwJ6JRSZ8KiT2KStwMkhivarNDy03drk8IpUGo0Wn.rMI075AdDIsZwmrwwu.uOOXmkfgrC+KxcMqdpzxovZlx5L6t2k7YPZD7VRKMggt1cIU+b9kSNLLD53imvQbKWXIIEKUpLuJqGE3foMgyPToEwheeXo6XZcegz.rrOri0DyGoDpMFTjq.iQNQg2vE3esvJ3UHl1efu2g9wzF.OBr3sgpPIiuT2tScMr80PeWWXGm1xhy5RPrfG+Rh.+GKWPRHAzH2szuKdyK9t3Uep.aQ2zJ.56g2aWi.p2E8.BFIsfCe6Q6sCTaFdA9IykcUWvb6POkYSEWm+sM2gFcRrefQtYRusYibuSLe0OPdY+VdTWCliQt7lR8lw4puHyH0AbGhrIFskv0HcluIbKCkC68iSdrCwgU20GZOwqWGFHWvy7WXpN0Edv+q3sdUG7e+OtUh.Qv84M+J5ni8sBcLNtm7IhdeyJKudk6s1FqrdICVLcfbg2yrxpKuw5UVekxJyur.iMprwZ2a4MV0Hlddr5qMw0Dy77blnyzbv4w6a.ui4JEKgW97bIWIdC6XHfj3xFgk4WLKe888OCPClZC9vcYhQkW9d7waOLJ1evCCsBfnNQZXtCsq0P23pAPkgg3inAqhdp7Ee.dCkvV0BaFjG7bsM3eVe8R2aiR2qLGpN9854ROv2gpsy3yOkbe4Hovm6QQzGSwL3JzR5oAKVGB61Ndj6X6TyZRkv3yy8+yNkkkyWyyQ4rWK+KMLl7gp9PSfnwR20e2L70ESV.bf0drJ7NH7hfrkpu93qsGS6pRhejYSVrc+oSiyLEZDbyeSPiIOA4GXJdqnLB7Vl0+52Pu23rJm+6JN+2yrs3ZSSdow2OabY8mZL81UUEMOgFWc.lcSUm1Ljp+Hy.iCEBM9b4l8JyWk+d+NpSU2+olYbA4GGqTwsuzCZ5LjAAZMg3Qh22S95Xvb4lAy1HFWBGiDQapmCev+E9jrXYbbtjEKKWT0JyTFHNI1+WKMwNWioApP6gCiR2XwCLm6eXlkTN.qnHD5XnI.eAQuFPPN5Bjic8sOge2vSjIO4wyd.BQA6Dd85jv+cdMYzbinIxJY3PZ7Y9gmvsVS9N3CJ731IJPNUU7shvb2rDSSASAZD9f20DJ.rXIAXM8cGEz22iYipPARRhW5TJ3fcsh5.cmgA3ZOLBpwwogWa.X9O6CH.StCg7OfnUzf3Hr5aLPIVkD35fOSZpKjF0lYBgxXwO3CM.v8UlrVH7.xb.upjYLArv0EhDAAHNAenIIgYkgFE8IJTjBLSmJT.35PE+bSekeCMiSGVPA2ihnE0fYZzwXayqhRPknK8bY0ki4SN9LFX9JG54hCrF3u33Pc3HiamQSKr4iXpL0irDU8UfnmxQ.Qc.y6wnGG7UzVy3.qySGCETYzNlFfd333xvXgrpgTXCNTFoviqqct7.03nQHoy006EIehQIdfE6ER3W0M35Tf9TJf3WatKT1jMnzbHGXEwe.MQDTSHBpV9wYRcp0b.dski6lNwwmJKO3IPQy7eWJb99WyGye94GRA+vIqSPOK++9p9yKK3J+yKSTGeGnd6n.+HneEkctMc.qCz1Sj1rigwxSECsY2gFOzSeqESIgZqUVY1uAEE0AQgJbaImTY+93sfF7z1LXr14c.S1zE4Y+yu8Kq4g+9kZSAN2Q7S4iWelZIVCg534c5Td5Sur5znULnCsurput0Uyx7U7ir6cdS8ir6VWsJttbx6sf1Xzpk81RZrMCyKTy6TpKlFAoweoYR2mxY0cCOv2yWVbPlRuEEhdzqGUyVZpLT03Xn8UUa3VTWpUjhq4uaKwqdd.Oq40RV7Zpt9eiofb4Wz2OnB6uQMytzVQm8J0J5qc5852V5MrGJDx7sGM8mh+hrWlvU2je7022v0R7qj1TUG5v722GKEiKV9XwLDbJB1MIUuXhYdiWLAlUb73WbsDTsf8IX0rJGERlhTyNpv2x2OFu6a0eq7hmCmeAav1qGBFqUlpMWcnWLQ+BiL29Kd1ih.Hd1.1Iz+5yRpN8YbAkXWe1ZKW5dqs9QGY0e.CKT9EGczfgQL6EiwRbXnkUOX5Ei.6jEEq.UrsH9D4gKdVeZHcwyv+4Eu3Yg.rEGDrhw.TRKzxCrPihbdeVICWfk4bgbMWtLvQt9alpHt0OUEwOVUQr7OUEwOUEwa8UQbCmf6mmdW5fobVyxeBeLA6H7B5Vdla5tkmZqupShuiTH8uvezJ04212JbpK8ceYcfImJNYW1t1aD7uB17a+x2xRb7F+YodqLYwJ+Txhe3IK9w8EOm8+qewyajDA2Dmw.K6P+irEuMFZm9y3y.7sGuugaad.NlT13TwkfmoKG.Q4Nx1Veql.wkutHtx0EwJWWDW85h3ZWWDu20Ew0e0HhIgpNL1efv0zv3fl0DOgStzdMyMqw+CFi.0X
                

                This was vey much inspired by @Mighty23 's approach but with some distinct differences. To be honest I was struggling with it and used chatGPT to figure out the anti-aliasing filter and linear interpolation functions, i.e. it isn't completed yet. Use a noise signal and compare the green with the red output to see the differences.

                Perhaps you could employ @oskarsh suggestion with downsampling the signal for further smoothing. Also if anyone can figure out how to compress the signal on the vertical axis based on the amplitude would be a true hero.

                Content.makeFrontInterface(400, 400);
                
                /* ======================================================================
                ==================== OSCILLOSCOPE DISPLAY BUFFER ========================
                ========================================================================*/
                
                // Variables
                const var pnl_Osc1 = Content.getComponent("pnl_Osc1");
                //const var Fx1 = Synth.getEffect("Fx1");
                const var Fx = Synth.getEffect("Fx"); // Your ScriptFx with an fft analyzer to reference.
                
                // Buffer Properties
                const var BUFFER = Synth.getDisplayBufferSource("Fx");
                const var BUF_OSC1 = BUFFER.getDisplayBuffer(0);
                const var BUF_LENGTH = 1024; // Reduced buffer length for stability
                const var BUF_PROPERTIES = {
                    "BufferLength": BUF_LENGTH,
                    "NumChannels": 1
                };
                
                BUF_OSC1.setRingBufferProperties(BUF_PROPERTIES);
                BUF_OSC1.setActive(true); // Activate the buffer
                
                const var TEMP_BUFFER = Buffer.create(BUF_LENGTH); // Temporary buffer for processing
                
                reg BUF_SIGNAL = false; // Initialize as false
                var scalingFactor = 1.0; // Dynamic scaling factor
                const var SCALE_DECAY = 0.98; // Smoothing factor for dynamic scaling
                
                // Interpolation Factor
                const var INTERPOLATION_FACTOR = 50; // Number of points to interpolate between samples
                
                // Visual Properties
                const var MAX_GHOSTS = 5; // Number of ghost trails
                const var COLOUR_BG = Colours.black;
                const var COLOUR_RAW = Colours.red; // Raw waveform color
                const var COLOUR_SMOOTH = Colours.green; // Smoothed waveform color
                const var COLOUR_SATURATED = Colours.yellow; // Color for saturated peaks
                const var STROKE_WIDTH1 = 2.0; // Smoothed waveform thickness
                const var STROKE_WIDTH2 = 1.0; // Ghost trail thickness
                const var OFFSET_SCALE = 10.0; // Vertical offset scale for ghost trails
                const var SMOOTH_WINDOW_SIZE = 15; // Smoothing window size for anti-aliasing
                const var SATURATION_THRESHOLD = 0.8; // Threshold for saturation
                
                // Create Paths
                const var oscPath = Content.createPath();
                const var rawPath = Content.createPath(); // Path for raw waveform
                const var ghostPaths = [];
                
                for (i = 0; i < MAX_GHOSTS; i++) 
                {
                    ghostPaths.push(Content.createPath());
                }
                
                var frameCount = 0;
                
                // Anti-Aliasing Filter Function
                var smoothed = [];
                inline function smoothBuffer(buffer, windowSize) 
                {
                    for (i = 0; i < buffer.length; i++) 
                    {
                        local sum = 0;
                        local count = 0;
                        for (j = -Math.floor(windowSize / 2); j <= Math.floor(windowSize / 2); j++) 
                        {
                            if ((i + j) >= 0 && (i + j) < buffer.length) 
                            {
                                sum += buffer[i + j];
                                count++;
                            }
                        }
                        smoothed[i] = sum / count;
                    }
                    return smoothed;
                }
                
                // Linear Interpolation Function
                inline function interpolateSamples(buffer, factor) 
                {
                    local interpolated = [];
                    for (i = 0; i < buffer.length - 1; i++) 
                    {
                        interpolated.push(buffer[i]);
                        for (j = 1; j < factor; j++) 
                        {
                            local t = j / factor;
                            interpolated.push(buffer[i] * (1 - t) + buffer[i + 1] * t); // Linear interpolation
                        }
                    }
                    interpolated.push(buffer[buffer.length - 1]);
                    return interpolated;
                }
                
                // ---------- Paint Routine ----------
                pnl_Osc1.setPaintRoutine(function(g) 
                {
                    g.fillAll(COLOUR_BG);
                
                    if (!BUF_SIGNAL) 
                    {
                        return; // If no signal, avoid unnecessary drawing
                    }
                
                    var width = this.getWidth();
                    var height = this.getHeight();
                    var midY = height / 2;
                
                    // Shift ghost paths
                    for (i = MAX_GHOSTS - 1; i > 0; i--) 
                    {
                        ghostPaths[i] = ghostPaths[i - 1];
                    }
                
                    oscPath.clear();
                    rawPath.clear();
                
                    // Copy buffer data and smooth it
                    BUF_OSC1.copyReadBuffer(TEMP_BUFFER);
                    var smoothedBuffer = smoothBuffer(TEMP_BUFFER, SMOOTH_WINDOW_SIZE);
                    var interpolatedBuffer = interpolateSamples(smoothedBuffer, INTERPOLATION_FACTOR);
                
                    // Calculate dynamic scaling factor
                    var peakLevel = TEMP_BUFFER.getPeakRange(0, BUF_LENGTH)[1];
                    scalingFactor = Math.max(0.1, Math.min(scalingFactor * SCALE_DECAY, 1 / peakLevel));
                
                    // Draw the raw waveform
                    var sample = TEMP_BUFFER[0];
                    rawPath.startNewSubPath(0, midY - sample * midY * scalingFactor);
                
                    for (i = 1; i < BUF_LENGTH; i++) 
                    {
                        var x = (i / BUF_LENGTH) * width;
                        sample = TEMP_BUFFER[i];
                        var y = midY - sample * midY * scalingFactor;
                        rawPath.lineTo(x, y);
                    }
                
                    // Draw the interpolated waveform
                    sample = interpolatedBuffer[0];
                    oscPath.startNewSubPath(0, midY - sample * midY * scalingFactor);
                
                    for (i = 1; i < interpolatedBuffer.length; i++) 
                    {
                        var x = (i / interpolatedBuffer.length) * width;
                        sample = interpolatedBuffer[i];
                        var y = midY - sample * midY * scalingFactor;
                        oscPath.lineTo(x, y);
                    }
                
                    ghostPaths[0] = oscPath;
                
                    // Draw ghost trails with vertical offset
                    for (i = MAX_GHOSTS - 1; i >= 0; i--) 
                    {
                        var opacity = 0.5 * (1 - i / MAX_GHOSTS);
                        var verticalOffset = OFFSET_SCALE * (i - MAX_GHOSTS / 2);
                        g.setColour(Colours.withAlpha(COLOUR_SMOOTH, opacity));
                        g.drawPath(ghostPaths[i], [0, verticalOffset, width, height], {"Thickness": STROKE_WIDTH2});
                    }
                
                    // Draw the raw waveform
                    g.setColour(COLOUR_RAW);
                    g.drawPath(rawPath, [0, 0, width, height], {"Thickness": 0.5});
                
                    // Draw the smoothed interpolated waveform
                    g.setColour(COLOUR_SMOOTH);
                    g.drawPath(oscPath, [0, 0, width, height], {"Thickness": STROKE_WIDTH1});
                });
                
                // ---------- Timer Callback ----------
                const var oscTimer = Engine.createTimerObject();
                oscTimer.setTimerCallback(function() 
                {
                    if (frameCount++ % 1 === 0) 
                    {
                        BUF_SIGNAL = Fx.getCurrentLevel(true) > 0.001; // Update if signal active
                        pnl_Osc1.repaint(); 
                    }
                });
                
                // Start the timer
                oscTimer.startTimer(30);
                
                
                mmprodM 1 Reply Last reply Reply Quote 3
                • mmprodM
                  mmprod @HISEnberg
                  last edited by

                  @HISEnberg @oskarsh @Mighty23 thanks guys- I’ll look into these and get back to you

                  For God so loved the world that he gave his one and only Son, that whoever believes in him shall not perish but have eternal life.
                  John 3:16

                  1 Reply Last reply Reply Quote 0
                  • mmprodM
                    mmprod @oskarsh
                    last edited by

                    Ok - I put a "sample and hold" node before the oscilloscope (is that what you meant by downsampling? @oskarsh ) and drew the oscilloscope path like @Mighty23 and @HISEnberg recommended. I got some decent results but unfortunately now HISE crashes after 5-10 seconds of opening! My hunch is that the timer interval is too fast or that the buffer size is too high. When I delete the code and the panel that is being painted, HISE doesn't crash.

                    //code thanks to mighty23
                    const var dp_analyser = Synth.getDisplayBufferSource("Script FX2");
                    const var rb_analyser = dp_analyser.getDisplayBuffer(0);
                    const var BUFFER_LENGTH = 512;
                    const var properties = {
                        "BufferLength": BUFFER_LENGTH,
                        "NumChannels": 1
                    };
                    rb_analyser.setRingBufferProperties(properties);
                    const var P1 = Content.getComponent("P1");
                    const var NUM_WAVEFORMS = 6;
                    const var waveformBuffers = [];
                    var time = 0;
                    
                    for (var i = 0; i < NUM_WAVEFORMS; i++) {
                        waveformBuffers[i] = rb_analyser.createPath(P1.getLocalBounds(0), [0, BUFFER_LENGTH, -8.0, 8.0], 0.0);
                    }
                    
                    var bufferIndex = 0;
                    var offset = 0;
                    
                    P1.setTimerCallback(function() {
                        var newPath = rb_analyser.createPath(
                            this.getLocalBounds(0), 
                            [offset, BUFFER_LENGTH + offset, -12.0, 12.0],
                            time * (bufferIndex + 1) * 0.2
                        );
                        
                        waveformBuffers[bufferIndex] = newPath;
                        bufferIndex = (bufferIndex + 1) % NUM_WAVEFORMS;
                        offset = (offset + 256) % BUFFER_LENGTH;
                        time += 0.1;
                        
                        this.repaint();
                    });
                    
                    P1.setPaintRoutine(function(g) {
                        var a = this.getLocalBounds(0);
                    
                            g.setColour(0xFFB8C043);
                            g.drawPath(waveformBuffers[i], a, 1);
                    });
                    
                    P1.startTimer(1);
                    

                    Any ideas?

                    Otherwise I may stick with a non-smoothed oscilloscope for this project - this seems like a very finicky process.

                    For God so loved the world that he gave his one and only Son, that whoever believes in him shall not perish but have eternal life.
                    John 3:16

                    HISEnbergH oskarshO M 3 Replies Last reply Reply Quote 0
                    • HISEnbergH
                      HISEnberg @mmprod
                      last edited by

                      @mmprod i was getting instant crashes too, I suspect the buffer doesn't clear so it just fills up and crashes. Did you try my version? I basically bypass the buffer altogether and just refer to the fft and draw it to the panel.

                      1 Reply Last reply Reply Quote 0
                      • oskarshO
                        oskarsh @mmprod
                        last edited by

                        @mmprod yes the sample and hold node is correct. Go a little easy on the timer. 10 or 20 should be enough.

                        The problem with the oscilloscope is that you draw many points that are not necessary basically overlapping points. To get better performance you need to simplify the path and drop points that are the same. There are many discussions on the juce forum about this

                        1 Reply Last reply Reply Quote 0
                        • M
                          Mighty23 @mmprod
                          last edited by

                          @mmprod said in How to draw super smooth Waveform?:

                          Any ideas?

                          I introduced a simplifyBuffer function that removes redundant points from the buffer based on a SIMPLIFICATION_TOLERANCE value.

                          const var dp_analyser = Synth.getDisplayBufferSource("HardcodedMasterFX1"); // or what you neeed
                          const var rb_analyser = dp_analyser.getDisplayBuffer(0);
                          const var BUFFER_LENGTH = 512;
                          const var properties = {
                              "BufferLength": BUFFER_LENGTH,
                              "NumChannels": 1
                          };
                          rb_analyser.setRingBufferProperties(properties);
                          const var P1 = Content.getComponent("P1");
                          const var NUM_WAVEFORMS = 6;
                          const var waveformBuffers = [];
                          const var SAMPLE_REDUCTION = 4; // Only process every 4th sample
                          var time = 0;
                          
                          for (var i = 0; i < NUM_WAVEFORMS; i++) {
                              waveformBuffers[i] = rb_analyser.createPath(
                                  P1.getLocalBounds(0), 
                                  [0, Math.floor(BUFFER_LENGTH/SAMPLE_REDUCTION), -8.0, 8.0], 
                                  0.0
                              );
                          }
                          
                          var bufferIndex = 0;
                          var offset = 0;
                          
                          P1.setTimerCallback(function() {
                              var newPath = rb_analyser.createPath(
                                  this.getLocalBounds(0), 
                                  [Math.floor(offset/SAMPLE_REDUCTION), 
                                   Math.floor((BUFFER_LENGTH + offset)/SAMPLE_REDUCTION), 
                                   -12.0, 12.0],
                                  time * (bufferIndex + 1) * 0.2
                              );
                              
                              waveformBuffers[bufferIndex] = newPath;
                              bufferIndex = (bufferIndex + 1) % NUM_WAVEFORMS;
                              offset = (offset + 256) % BUFFER_LENGTH;
                              time += 0.1;
                              
                              this.repaint();
                          });
                          
                          P1.setPaintRoutine(function(g) {
                              var a = this.getLocalBounds(0);
                              g.setColour(0xFFB8C043);
                              for (var i = 0; i < waveformBuffers.length; i++) {
                                  g.drawPath(waveformBuffers[i], a, 1);
                              }
                          });
                          
                          P1.startTimer(20);
                          

                          Fix this value according your "downsampling":

                          const var SAMPLE_REDUCTION = 4; // !!!!!!!! Only process every 4th sample
                          

                          We need to optimize the scope design; this version could be a starting point. You can adjust the SIMPLIFICATION_TOLERANCE value to control how much the buffer data is simplified, "skipping" redundant points.

                          That said, I realize this discussion might be going off-topic and potentially not fair to other users. Let me know if it would be better to start a dedicated thread for this topic.

                          Free Party, Free Tekno & Free Software too

                          1 Reply Last reply Reply Quote 0
                          • mmprodM
                            mmprod
                            last edited by

                            Thanks guys for the help- the closest I got was simply using the original code with the higher timer value like how @oskarsh suggested. But of course the animation is more choppy.

                            @HISEnberg and @Mighty23 I tried both your methods- these work well but I can’t wrap my head around how to ‘restyle’ it to a ‘smooth’ waveform. I’m also getting the occasional HISE crash which may be a problem for future plug-in users.

                            Im going to use the vanilla oscilloscope for my project. Once again, thanks for your generous help!

                            For God so loved the world that he gave his one and only Son, that whoever believes in him shall not perish but have eternal life.
                            John 3:16

                            1 Reply Last reply Reply Quote 0
                            • First post
                              Last post

                            32

                            Online

                            1.7k

                            Users

                            11.8k

                            Topics

                            102.7k

                            Posts