Is an Audio In OLED oscilloscope possible?

Nice work for getting this working!

I’m just trying to port this to the other daisy way, with vs code.

Getting a little stuck with porting properly. Using the patch’s OLED screen. Wanted to port exactly for now, but getting stuck.

Could be the micros() call, or the updating screen is slightly different with oled library in libdaisy.

#include "daisysp.h"
#include "daisy_patch.h"
#include "CircularBuffer.h"

#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
using namespace daisy;
using namespace daisysp;

DaisyPatch patch;
#define DISPLAY_WIDTH 128
#define DISPLAY_HEIGHT 64
#define CHUNK 6

const unsigned long period = 16777; //period of time to perform an OLED update, in microseconds
unsigned long previousTime, currentTime;
uint64_t currentCount, previousCount;
uint8_t hKnob, vKnob;
float addIn, avg; //average of samples
int lastSmpl; //used in OLED draw
unsigned long avgPeriod = 6; //number of 6 sample 'chunks' to average, larger period means slower horizontal scaling
int vScale = 2; //vertical scaling amount
int previousValue;
CircularBuffer<float, DISPLAY_WIDTH> buf;
bool draw;
void updateOLED(int x, float val);
void starter();

static void AudioCallback(AudioHandle::InputBuffer  in,
                          AudioHandle::OutputBuffer out,
                          size_t                    size)
{    
    for(size_t i = 0; i < size; i++)
    {
        for(size_t chn = 0; chn < 2; chn++)
        {
            out[chn][i] = in[chn][i]; //bypass audio
            addIn += in[chn][i];      //continuously add up incoming values
        }
    }
    currentCount++;
    if(currentCount - previousCount >= avgPeriod)
    {
        avg += addIn;
        avg /= CHUNK * avgPeriod;
        buf.push(avg * vScale);
        if(buf.isFull())
        {
            buf.shift();
        }
        avg           = 0;
        addIn         = 0;
        draw          = true;
        previousCount = currentCount;
    }
}

int main(void)
{
    
    patch.Init();
    starter();
    patch.StartAudio(AudioCallback);
    patch.StartAdc();
    patch.display.Fill(false);
      while(1)
    {
        unsigned long currentTime = patch.seed.system.GetNow();
            if(draw)
            {
                if(currentTime - previousTime >= period)
                {
                    patch.display.Fill(false);
                    for(int i = DISPLAY_WIDTH; i > 0; i--)
                    {
                        float y = buf[i];
                        int   x = i;
                        updateOLED(x, y);
                    }
                    patch.display.Fill(true);
                    patch.display.Update();
                    draw         = false;
                    previousTime = currentTime;
                }
                
            }
            avgPeriod = 6;
            vScale = 2;
            
    }
}

void starter()
{
    lastSmpl = 16;
    draw = false;
    patch.SetAudioBlockSize(CHUNK);
}

void updateOLED(int x, float val) {
  float y = (val + 1) / 2 * DISPLAY_HEIGHT; //map the incoming averaged value from -1, 1 to 0, displayHeight
  float currentSmpl = constrain(y, 0, DISPLAY_HEIGHT - 1); //create currentSmpl value from y and constrain to displayHeight
  patch.display.DrawLine(x, lastSmpl, x + 1, currentSmpl, true); //draw a line from last sample to current sample
  lastSmpl = currentSmpl; //reassign last sample as the current one
}


If anyone with a Patch could have a look that’d be great. I think things are roughly in the right places, but I’m just getting a blank white screen and nothing else.

1 Like

this can be refined slightly but it works:

#include "daisysp.h"
#include "daisy_patch.h"
#include "CircularBuffer.h"

#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
using namespace daisy;
using namespace daisysp;

DaisyPatch patch;
#define DISPLAY_WIDTH 128
#define DISPLAY_HEIGHT 64
#define CHUNK 6
CircularBuffer<float, DISPLAY_WIDTH> buf;
int lastSmpl; //used in OLED draw

unsigned long previousTime, currentTime;
uint64_t currentCount, previousCount;
uint8_t hKnob, vKnob;
float addIn, avg; //average of samples
int avgPeriod = 6; //number of 6 sample 'chunks' to average, larger period means slower horizontal scaling
int vScale = 2; //vertical scaling amount
int previousValue;

void updateOLED(int x, float val);
void starter();

static void AudioCallback(AudioHandle::InputBuffer  in,
                          AudioHandle::OutputBuffer out,
                          size_t                    size)
{    
    //  for(size_t i = 0; i < size; i++)
    //     {
    //         out[0][i] = in[0][i];
    //         out[1][i] = in[1][i];
    //     }
    for(size_t i = 0; i < size; i++)
    {
        for(size_t chn = 0; chn < 2; chn++)
        {
            out[chn][i] = in[chn][i]; //bypass audio
            addIn += in[chn][i];      //continuously add up incoming values
        }
    }
    currentCount++;
    if(currentCount - previousCount >= avgPeriod)
    {
        avg += addIn;
        avg /= CHUNK * avgPeriod;
        buf.push(avg * vScale);
        if(buf.isFull())
        {
            buf.shift();
        }
        avg           = 0;
        addIn         = 0;
        //draw          = true;
        previousCount = currentCount;
    }
}

int main(void)
{
    lastSmpl = 16;
    patch.Init();
    patch.StartAudio(AudioCallback);
    while(1)
        {
            for (int i = DISPLAY_WIDTH; i > 0; i--)
            {
                //updateOLED(i, 1.0);
                float y = buf[i];
                int x = i;
                updateOLED(x, y); 
            }
            patch.display.Fill(false);
        }
}


void updateOLED(int x, float val) 
{
    float y = (val + 1) / 2 * DISPLAY_HEIGHT; //map the incoming averaged value from -1, 1 to 0, displayHeight
    float currentSmpl = constrain(y, 0, DISPLAY_HEIGHT - 1); //create currentSmpl value from y and constrain to displayHeight
    patch.display.DrawLine(x, lastSmpl, x + 1, currentSmpl, true); //draw a line from last sample to current sample
    lastSmpl = currentSmpl; //reassign last sample as the current one
    //patch.display.DrawLine(x,val,0,DISPLAY_HEIGHT/2,true);
    patch.display.Update();
}

void UpdateOled()
{
    patch.display.Fill(false);

    patch.display.SetCursor(0, 0);
    std::string str  = "Hello";
    char*       cstr = &str[0];
    patch.display.WriteString(cstr, Font_7x10, true);

    str = "Working:";
    patch.display.SetCursor(0, 30);
    patch.display.WriteString(cstr, Font_7x10, true);

    patch.display.SetCursor(70, 30);
    cstr = "yes";
    patch.display.WriteString(cstr, Font_7x10, true);

    patch.display.Update();
}

@donutshoes you ok with me porting this? if you have a github happy for you to host that code on there if you’re ok with people using your work.

1 Like

Great to hear you got it working! I don’t mind you porting, I’m still quite new to developing, haven’t really used github yet :sweat_smile:

If anyone’s still here checking this out, I’m still having problems with my potentiometers with the Daisy Seed and I’m still interested in hearing any ideas for potential solutions

Hey thanks for this! How are you incorporating the CircularBuffer.h file with this? I was trying to use the one that OP provided but the .tpp file was giving me problems

I just chucked the header and cpp file into the same directory and linked with quotes

#include "CircularBuffer.h"

instead of <CircularBuffer>