Getting to know Daisy (C++)

daeg

Well-known member
So you're a guitarist and a hobbyist pedal builder. The new and exciting Electrosmith Daisy Seed module just arrived at your door. What do you do next?

Well... I can't answer that question for you because I'm lost myself. Why don't we use this thread to try to get over the learning curve together.

My goals are to understand the Daisy Wiki, understand the template for writing C++ algorithms and work out some basic functionality for a guitar pedal. I'm a capable scripter and wasn't half bad at working with FV-1 ASM code, but have never used any language like C++ and am finding this intimidating. A few of you here are probably in a similar place with similar goals, so let's learn from each other.
 
So if I've kept your attention, you're interested in developing your own patches and probably already get the gist of how the Daisy Seed module is going to work, what the layout for the PedalPCB Terrarium is going to look like and what types of controls you have to work with -- so let's get straight to the C++ examples and see if we can start to build some understanding. First up; the Daisy Petal C++ Template.

C++:
// Basic Template for DaisyPetal
#include "daisy_petal.h"

using namespace daisy;

DaisyPetal hw;

void AudioCallback(float *in, float *out, size_t size)
{
    hw.DebounceControls();
    hw.UpdateAnalogControls();
    for(size_t i = 0; i < size; i += 2)
    {
        out[i]     = in[i];
        out[i + 1] = in[i + 1];
    }
}

int main(void)
{
    hw.Init();
    hw.StartAdc();
    hw.StartAudio(AudioCallback);
    for(;;) {}
}
 
^ How do we post nicely formatted, syntax highlighted C++ code like that? The BBCode on this forum already supports it. Hit the gear looking button that says 'Togge BBCode' when you hover over it, this will let you see under the hood of your post. Then do the following without the spaces.

[ c o d e = c p p ] somecodeyoupasted [ / c o d e ]

If we really get going, maybe Mr. PCB can create a button for us to make that easy.
 
The first couple of lines I can explain with no experience with C++.

C++:
// This is a comment in C++
// You can put any text in this this line for reference; the algorithms name, your name, a description of what it does or how to use it.


The next line is an include directive. This loads the C++ code from another file and inserts it there. This can help you break up your code or load specific components without typing it all out. Very useful.
C++:
#include "daisy_petal.h"

Not sure what is in the daisy_petal.h file yet. Maybe that will be the next post...
 
The first couple of lines I can explain with no experience with C++.

C++:
// This is a comment in C++
// You can put any text in this this line for reference; the algorithms name, your name, a description of what it does or how to use it.


The next line is an include directive. This loads the C++ code from another file and inserts it there. This can help you break up your code or load specific components without typing it all out. Very useful.
C++:
#include "daisy_petal.h"

Not sure what is in the daisy_petal.h file yet. Maybe that will be the next post...

So theoretically if you like a specific chunk of eq code, you could save that separate and paste it into any new set of pedal code?
 
Thanks for starting this thread. I also want to learn more about programming for the Daisy seed. Coming into it with very little programming and nothing in C++
 
So lets take this line by line....


C++:
#include "daisy_petal.h"
This instructs our compiler to include the Daisy Petal interface functions. This allows us to utilize the pre-written core functions of the Daisy Petal. We could use the daisy_seed.h header file instead, but the Petal offers us some shortcuts that will make life easier. Eventually we will likely adapt this into our own custom fit set of routines, but for now the Terrarium PCB is designed to use the standard Petal functions (with a couple exceptions).

C++:
using namespace daisy;
This allows us to use all of the functions in the "daisy" namespace without having to implicitly specify the namespace each time. It's basically a shortcut to make code cleaner / easier to read. For example, without this directive the next line would read daisy::DaisyPedal hw;".

C++:
DaisyPetal hw;
This creates an object that allows us access to the DaisyPetal hardware.

C++:
void AudioCallback(float *in, float *out, size_t size)
{
    hw.DebounceControls();
    hw.UpdateAnalogControls();
    for(size_t i = 0; i < size; i += 2)
    {
        out[i]     = in[i];
        out[i + 1] = in[i + 1];
    }
}
The AudioCallback function will be executed for each block of audio that is to be processed. *in is a pointer to the input buffer, *out is a pointer to the output buffer, and size is the length of the block (48 samples by default).

C++:
hw.DebounceControls();
When toggle switches / footswitches are switched the contacts tend to "bounce" briefly, creating many false triggers. We generally don't have to worry about this much with analog circuits, but in the digital world the switches need to be low-pass filtered. This function takes care of that.

C++:
hw.UpdateAnalogControls();
This reads the current state of analog controls (pots, switches, etc) so we can process them when needed.

C++:
    for(size_t i = 0; i < size; i += 2)
    {
        out[i]     = in[i];
        out[i + 1] = in[i + 1];
    }
This is where your actual effect processing will take place. The code inside the "for" loop will execute once for each sample (48 times per block by default). The Daisy audio is interleaved, so we can access the left and right channels simultaneously for each sample.

in[i] is the left channel input.
in[i+1] is the right channel input.
out[i] is the left channel output
out[i+1] is the right channel output.

The line out[i] = in[i]; passes the left input directly to the left output with no other processing.
Similarly out[i+1] = in[i+1]; passes the right input directly to the right output with no processing.

We could increase the left channel amplitude by multiplying:
out[i] = in[i] * 2.0f; (gain of 2)
Or could attenuate the left channel by dividing (or multiplying by a decimal less than 1)
out[i] = in[i] * 0.5f; (attenuate by 1/2)

The f after a decimal number tells the compiler that this should be treated as a float (floating point) data type. Without the f suffix the compiler could round your decimal value up or down to the nearest whole integer, or in some cases throw an exception (error) and just not compile at all.

C++:
int main(void)
{
    hw.Init();
    hw.StartAdc();
    hw.StartAudio(AudioCallback);
    for(;;) {}
}
The main() function is the entry point for most C++ programs. This is where program execution begins.

C++:
hw.Init();
This initializes the Daisy hardware.

C++:
hw.StartAdc();
This starts the Analog to Digital conversion so we can access the analog audio inputs

C++:
hw.StartAudio(AudioCallback);
This instructs the Seed to begin processing audio input by sending blocks to our AudioCallback function above.

If all of this doesn't make sense initially, don't panic... Most of this is boilerplate code that you will copy/paste into every new program. It'll all come together once we start writing an actual algorithm that does something.
 
Last edited by a moderator:
I think the FV-1 is staying in production. ElectroSmith (the company that created the Daisy) also sells FV-1 chips. The primary interest at Electro Smith is providing the Daisy for use in synthesizer applications, but they also understand it fits in the effect pedal category as well (which serves both guitar players and synth players).

I think that anything an FV-2 chip can do, the Daisy board can do with much more powerful processing and more memory. Sort of like the way that the FV-1 chip is able to do much more than the PT2399 delay chips. But of course the FV-1 chip is more expensive than a PT2399, and the Daisy is more expensive than the FV-1.

I am really interested to see what kinds of effects will be possible with the Daisy that are out of reach of the FV-1. Those will be the game changers.
 
Yeah I like what zgrav said, I intend to take a both/and approach. I think the fv-1 is great for some applications and the small package and lower cost, I plan to keep using it. But, the daisy will open up new frontiers And better quality for some effects where the fv-1 is lacking. Anyway, just mentioning that to those that are just getting started on fv-1 dev board, I personally don’t think it’s a waste to still get into it.
 
I am really interested to see what kinds of effects will be possible with the Daisy that are out of reach of the FV-1. Those will be the game changers.

Just for a point of reference, the Daydream is a three-tap delay (approx 1000ms total combined delay time) each with a simple high-pass filter... This pretty much maxes out the instruction count and RAM of the FV-1.

With the Daisy I was able to run 50 taps (yes, 50) each with resonant band-pass filters, and 1000ms per tap. I hadn't hit the maximum at this point, I was just tired of adding more taps. :ROFLMAO:
 
So lets take this line by line....

Beautiful write-up. Enormously helpful. Exactly what I envisioned this thread accomplishing. Hope we can keep it going.

I was happy to wake up this morning and see that you created a DSP sub-forum. I've had my fingers crossed for that for a long while.
 
Just for a point of reference, the Daydream is a three-tap delay (approx 1000ms total combined delay time) each with a simple high-pass filter... This pretty much maxes out the instruction count and RAM of the FV-1.

With the Daisy I was able to run 50 taps (yes, 50) each with resonant band-pass filters, and 1000ms per tap. I hadn't hit the maximum at this point, I was just tired of adding more taps. :ROFLMAO:

That's very encouraging.

There was a guy on the Spin forum that had a way of creating a convincing Spring Reverb using a large number of all-pass filters, but was ultimately held back by the delay ram or number of registers (can't remember, but here is the thread). In fact, I was planning on buying a Catalinbread Topanga to study the code since it's FV-1 based and pretty highly regarded for 'authentic' surf drip sounds.
 
We could increase the left channel amplitude by multiplying:
out[i] = in[i] * 2.0f; (gain of 2)
Or could attenuate the left channel by dividing (or multiplying by a decimal less than 1)
out[i] = in[i] * 0.5f; (attenuate by 1/2)

Interesting...

Can we use the asterisk to multiply two signals? Make a simple ring modulator like this:
C++:
out[i] = in[i] * in[i + 1];

On the FV-1, this would look like:
Code:
RDAX ADCL, 1
MULX ADCR
WRAX ADCL, 0
 
The AudioCallback function will be executed for each block of audio that is to be processed. *in is a pointer to the input buffer, *out is a pointer to the output buffer, and size is the length of the block (48 samples by default).

Based on this thread, with the default block size (48), the Daisy / Terrarium is going to have 1ms latency on audio passthrough (ie when 'bypassed'). I can live with that.
 
Back
Top