As a means to control the LEDs on the pepper, I have created a square function - based on the one at the oscillator library - in which pulse width is one of the arguments.

However, I get the error "no matching function for call to 'squarePWM'" when I use "context", and no output at all anyway when I use any number in the first argument.

I am attaching the code here:

#include <Bela.h>
#include <cmath>
#include <libraries/math_neon/math_neon.h>
#include <vector>

int fs;
float phase_;
float Width;
float out;
float frequency_;
float invSampleRate_ = 1 / fs;
std::vector<int> ledPins = {6, 7, 10, 2, 3, 0, 1, 4, 5, 8}; // Bela Pepper Pin Numbering
std::vector<float> analogInput(8);

void computePhase()
{
	phase_ += 2.0f * (float)M_PI * frequency_ * invSampleRate_;
	if(phase_ > M_PI)
		phase_ -= 2.0f * (float)M_PI;
}

float squarePWM(int fs, float Width)
{
	if(phase_ > Width)
	{
		out = 1;
	}
	else
	{
		out = 0;
	}
	computePhase();
	return out;
}

bool setup(BelaContext *context, void *userData)
{
	for(unsigned int i = 0; i < 10; i++)
	{
		pinMode(context, 0, ledPins[i], OUTPUT);
	}
	

	return true;
}


void render(BelaContext *context, void *userData)
{
		for(unsigned int n = 0; n < context->analogFrames; n++) 
		{
			for(unsigned int m = 0; m < 8; m++)
			{
				analogInput[m] = analogRead(context, n, m);
			}
		
		}
		
		for(unsigned int n = 0; n < context->digitalFrames; n++)
		{
			
			for(unsigned int m = 0; m < 2; m++)
			{
				digitalWriteOnce(context, n, ledPins[m], squarePWM(context, analogInput[0]));
			}
			
			for(unsigned int m = 2; m < 8; m++)
			{
				digitalWriteOnce(context, n, ledPins[m], squarePWM(context, analogInput[m - 1]));
			}
			
			for(unsigned int m = 8; m < 10; m++)
			{
				digitalWriteOnce(context, n, ledPins[m], squarePWM(context, analogInput[7]));
			}
			
		}
}

void cleanup(BelaContext *context, void *userData)
{
	
}

Please let me know if I am missing something here : ) Thank you.

The "no matching function for call to" means that even if there is a function with the same name, the list of parameters it expects is different from the one that you are using in your call. You'll see that you have

float squarePWM(int fs, float Width)

in the function definition but you are calling squarePWM(context, analogInput[0]). So it expects int and float but you are passing BelaContext* and float. As you are not using fs in the function, you can remove it from the definition's argument list and you can remove context from the function call.

Another issue with the code is that there is a single phase variable (the global phase_) but you are using it for several independent channels, and it gets incremented at every channel so the result will be wonky (higher PWM clock, and the brightness won't be quite right). If you want to use a single phase_ variable across all channels it's fine, but you should not call updatePhase() from within squarePWM() (which gets called several times per frame), but rather only once per frame.

Hi! Thanks for the quick reply! I have fixed the issues you mention but I still can not get it to work.

I now have some blinking lights when the pots are close to the minimum value and the brightest anywhere else.


#include <Bela.h>
#include <cmath>
#include <libraries/math_neon/math_neon.h>
#include <vector>

int fs = 44100;
float phase_;
float Width;
float out;
float invSampleRate_ = 1 / fs;
std::vector<int> ledPins = {6, 7, 10, 2, 3, 0, 1, 4, 5, 8}; // Bela Pepper Pin Numbering
std::vector<float> analogInput(8);

void computePhase()
{
	phase_ += 2.0f * (float)M_PI * 440 * invSampleRate_;
	if(phase_ > M_PI)
		phase_ -= 2.0f * (float)M_PI;
}

float squarePWM(float Width) // map Width to be 0 <-> 2.0f* (float)M_PI
{
	if(phase_ < Width)
	{
		out = 1;
	}
	else
	{
		out = 0;
	}
	return out;
}

bool setup(BelaContext *context, void *userData)
{
	for(unsigned int i = 0; i < 10; i++)
	{
		pinMode(context, 0, ledPins[i], OUTPUT);
	}
	

	return true;
}


void render(BelaContext *context, void *userData)
{
		for(unsigned int n = 0; n < context->analogFrames; n++) 
		{
			for(unsigned int m = 0; m < 8; m++)
			{
				analogInput[m] = analogRead(context, n, m);
			}
		
		}
		
		for(unsigned int n = 0; n < context->digitalFrames; n++)
		{
			
			for(unsigned int m = 0; m < 2; m++)
			{
				digitalWriteOnce(context, n, ledPins[m], squarePWM(analogInput[0]));
			}
			
			for(unsigned int m = 2; m < 8; m++)
			{
				digitalWriteOnce(context, n, ledPins[m], squarePWM(analogInput[m - 1]));
			}
			
			for(unsigned int m = 8; m < 10; m++)
			{
				digitalWriteOnce(context, n, ledPins[m], squarePWM(analogInput[7]));
			}
			
		}
	
	computePhase();
}

void cleanup(BelaContext *context, void *userData)
{
	
}

another issues you have is that your analogInput[] variables, whose content you pass to squarePWM() have a range of 0 to 1, while your phase goes from -M_PI to M_PI, so the comparison (phase_ < Width) is always true at least half of the time when phase_ < 0, independently from your analog inputs values. You should rescale your phase_ to be between 0 and 1, which actually simplifies the computePhase() function significantly:

void computePhase()
{
	phase_ += 440 * invSampleRate_;
	if(phase_ >= 1)
		phase_ -= 1;
}

oh another thing:

int fs = 44100;
float invSampleRate_ = 1 / fs;

as fs is an integer, 1 / fs is an integer division. That means that the result will be an integer, and 1 / 44100 is 0. This fixes your invSampleRate to 0, which is not going to work. You have several workarounds to this, e.g.:

  • making fs a float, then the division will be between a float and an int, so the result will be a float.
  • explicitly make one of the two arguments a float, i.e.:
    • 1.f / fs or 1 / float(fs)

However, the best way to do it is to not hardcoded 44100 and instead, inside setup(), do:

invSampleRate = 1 / context->digitalSampleRate;

as context->digitalSampleRate is already a float, then you won't have problems here.

The last problem you have is that you are not calling updatePhase() once per frame, but once per block (i.e.: every 16 frames by default). This means that the effective sampling rate of your PWM carrier is 440/16, i.e.: approx 27.5Hz, which leads to visible flickering. You shuold move updatePhase() up three lines into the for(unsigned int n = 0; n < context->digitalFrames; n++) loop.

Jeez! That makes a lot of sense. Fixed and working! Thanks.