Calculating variables at compile time

Hi.

I am currently in the process of writing a library, which is able to output wavetable audio waves at a certain note. As I want this library to be use able across several microcontrollers and vary the sampling speed per program, to suit the need of various microcontrollers and desired audio quality. I want to be able to calculate an array of note values based on the sampling speed.

So lets say I want an array filled with compiler calculated values, which will be called Sn(y1,y2,..., yn), the values of Sn are calculated by using another Array, which will be called Sb(x1,x2.... xn) and the sample frequency s, through the formula yn = f(xn,s). I want the compiler to calculate Sn, so Sb will not clog up the memory and save on calculations that have to be run at run time.

Does anybody know a way of doing this, or perhaps knows in which direction to point me?

Thanks a bunch in advance.

So lets say I want an array filled with compiler calculated values

Compilers don't calculate values. That all happens at run time.

What it sounds like is that you should have different arrays defined, in #ifdef/#endif blocks, so the compiler only sees the set that is for the hardware it is compiling for.

PaulS: Compilers don't calculate values.

Well, actually they do. But only when everything involved is a compile-time constant.

@jortband, is that the case? Are you building tables of constants?

jortband: Does anybody know a way of doing this, or perhaps knows in which direction to point me?

Make some code, or a script (eg. in Perl, Lua, etc.) to generate these constants. Put them into an include file and put #ifdef around them so the compiler selects the right one.

I suggest you put the constants thus calculated into PROGMEM.

http://www.gammon.com.au/progmem

You could even do it on the Arduino if that is easiest. Make a small sketch that calculates your constants and outputs to serial. Then copy from serial and paste into your include file.

Yes, I am indeed trying building tables of constants. I want the compiler to convert and array filled with frequencies corresponding to note frequencies, into and array of constants my library will use.

Maybe this is going a bit to deep into the workings of my library, but it might clarify things. I have an array of frequencies,, in which the index corresponds to a midi note, and the value of that index corresponds to the frequency of that note. However the frequencies are all floats, so a bit heavy on the memory side. For my library I convert these values to a 32-bit delta value, which is used to increment an accumulator, which in turn is used to cycle trough the wavetable, the size of this delta determines the speed at which the cycle repeats and thus the pitch/note of the resulting wave. This means that for converting the frequency array to the delta array I need the sampling frequency. As this process only has to be done once and I only need the resulting delta array I want to let the compiler calculate this for me.

[quote author=Nick Gammon link=topic=271677.msg1914873#msg1914873 date=1412897379] You could even do it on the Arduino if that is easiest. Make a small sketch that calculates your constants and outputs to serial. Then copy from serial and paste into your include file. [/quote] [quote author=Nick Gammon link=topic=271677.msg1914870#msg1914870 date=1412897301]

jortband: Does anybody know a way of doing this, or perhaps knows in which direction to point me?

Make some code, or a script (eg. in Perl, Lua, etc.) to generate these constants. Put them into an include file and put #ifdef around them so the compiler selects the right one.

I suggest you put the constants thus calculated into PROGMEM.

http://www.gammon.com.au/progmem [/quote]

I know how to calculate the constants, in different programs (currently using plain old excel), however this does not provide me with the flexibility of using the compiler to do this process for me.

So my question still remain, does anybody know how to let values be calculated by the compiler.

Is there a simple (linear) relationship? If there is you could have something like a standard table, and multiply by an adjustment.

eg.

#if defined (__AVR_ATmega328P__)
  const float ADJUSTMENT = 1.5; 
#elif defined (__AVR_ATmega168__)
  const float ADJUSTMENT = 2.3; 
#endif 

const float foo [] PROGMEM = {
  23.45 * ADJUSTMENT,
  12.34 * ADJUSTMENT,
  42.42 * ADJUSTMENT,
  88.64 * ADJUSTMENT,
  // and so on ...
};

void setup () { }
void loop () { }

[quote author=Nick Gammon link=topic=271677.msg1914906#msg1914906 date=1412900078] Is there a simple (linear) relationship? [/quote]

And if the answer is "no" you might just have to provide a bit more detail, like what this function does.

I don't think it wouldt have to be strictly linear. You could do something like this:

#define A  1.112
#define B  (sqrt(A)*43.26)/(1-cos(A))
#define C  A*.45+tanh(B)*11.2-A*A

float table[] = {A, B, C};

FWIW the difference between any any ascending or descending note on the even tempered scale is an irrational number that is the twelfth root of 2. Thus there is an easy method of calculating any note... The root is a constant and so is the difference between the various processors and it should be a trivial task to calculate the tables required with Excel..

Bob

jboyton:
I don’t think it wouldt have to be strictly linear. You could do something like this:

#define A  1.112

#define B  (sqrt(A)43.26)/(1-cos(A))
#define C  A
.45+tanh(B)11.2-AA

float table = {A, B, C};

It looks like you are right. I didn’t know you could do that. :slight_smile:

I wonder what functions are supported, since this is clearly a compile-time calculation.

#define A  1.112
#define B  (sqrt(A)*43.26)/(1-cos(A))
#define C  A*.45+tanh(B)*11.2-A*A

const float table[3] = {A, B, C};

void setup ()
  {
  Serial.begin (115200);
  Serial.println ();

  for (size_t i = 0; i < 3; i++) 
    Serial.println(table[i]);

  }  // end of setup

void loop () { }

Output:

1.11
81.88
10.46

Maybe documented here: https://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html

[code]
#include <avr/pgmspace.h>    //to store values in progmem

#define samplingfrequency 15000
#define AccumMax 4294967295  //max value of a 32-bit value
#define aFreq 1.05946309435929526
#define lowA 27.5

//filling the array with a compiler generated value
float midiToFreq[3] PROGMEM = {1,pow(aFreq,69-21) * lowA, AccumMax * ((pow(aFreq,69-21) * lowA)/samplingfrequency)};

void setup(){
  Serial.begin(115200);
  for(byte i = 0; i<3;i++){
   Serial.println(pgm_read_float(&midiToFreq[i]));
  }
  
}


void loop(){
  
}

Hi thank you guys for the replies.

Storing in progmem is of course the best idea and somehow I needed a reminder of this, so thank you guys.
For now I have this code working and it seems to do the job.

Don’t mind the various functions, in the array declaration, this was just for testing purposes. The final function should be the same for each entry and only have one variable (the index number). As of yet I have the tedious task to copy paste all this 128 (the final array will have 128 entries) times and change the value for each one. I was wondering if somebody knows a way to do this with a recursive function (read for loop)?[/code]

What value changes? I still don't understand your objection to pre-calculating the values in spreadsheet and pasting them into a .cpp file that you include into your project.

If you could give a concrete statement of how these 128 entries are calculated (what is the formula?) and in what way the calculations changes for different clock speeds we might be able to help.

[quote author=Nick Gammon link=topic=271677.msg1917041#msg1917041 date=1413059162] What value changes? I still don't understand your objection to pre-calculating the values in spreadsheet and pasting them into a .cpp file that you include into your project.

If you could give a concrete statement of how these 128 entries are calculated (what is the formula?) and in what way the calculations changes for different clock speeds we might be able to help. [/quote]

Hi, I wanted the sampling frequency to be variable, as on the "slower" microprocessors you might want the sampling frequency to be just enough and on the "faster" microprocessors you might want the sampling frequency a bit higher, so you are able to generate a better quality signal. As I am also using the library I am creating for prototyping I want to be able to try different sampling frequencies to try out which quality/performance trade of works best for me. The equations I use is: AccumMax * ((pow( aFreq, x-21 ) * lowA)/samplingfrequency), the x is the index of the array and the samplefrequency is the variable I want to change. For now I have just copy pasted everything in the array declaration and changed the x accordingly. But of course doing this through a for loop, would me much more efficient from a coding perspective. So my current question is, can you do this?

You can’t do “for” loops at compile time, no.

The example below shows how you could easily make a table of constants, however have the calculation done at compile time. You said you want to vary x, so that is what is passed to FUNC, and the define then evaluates out to the function, applied for each x, in the table.

const float AccumMax = 3;
const float aFreq = 1.2;
const float lowA = 16;
const float samplingfrequency = 1000;

#define FUNC(x) AccumMax * ((pow( aFreq, x-21 ) * lowA)/samplingfrequency)

const float myTable [128] = {
  FUNC(0),FUNC(1),FUNC(2),FUNC(3),FUNC(4),FUNC(5),FUNC(6),FUNC(7),
  FUNC(8),FUNC(9),FUNC(10),FUNC(11),FUNC(12),FUNC(13),FUNC(14),FUNC(15),
  FUNC(16),FUNC(17),FUNC(18),FUNC(19),FUNC(20),FUNC(21),FUNC(22),FUNC(23),
  FUNC(24),FUNC(25),FUNC(26),FUNC(27),FUNC(28),FUNC(29),FUNC(30),FUNC(31),
  FUNC(32),FUNC(33),FUNC(34),FUNC(35),FUNC(36),FUNC(37),FUNC(38),FUNC(39),
  FUNC(40),FUNC(41),FUNC(42),FUNC(43),FUNC(44),FUNC(45),FUNC(46),FUNC(47),
  FUNC(48),FUNC(49),FUNC(50),FUNC(51),FUNC(52),FUNC(53),FUNC(54),FUNC(55),
  FUNC(56),FUNC(57),FUNC(58),FUNC(59),FUNC(60),FUNC(61),FUNC(62),FUNC(63),
  FUNC(64),FUNC(65),FUNC(66),FUNC(67),FUNC(68),FUNC(69),FUNC(70),FUNC(71),
  FUNC(72),FUNC(73),FUNC(74),FUNC(75),FUNC(76),FUNC(77),FUNC(78),FUNC(79),
  FUNC(80),FUNC(81),FUNC(82),FUNC(83),FUNC(84),FUNC(85),FUNC(86),FUNC(87),
  FUNC(88),FUNC(89),FUNC(90),FUNC(91),FUNC(92),FUNC(93),FUNC(94),FUNC(95),
  FUNC(96),FUNC(97),FUNC(98),FUNC(99),FUNC(100),FUNC(101),FUNC(102),FUNC(103),
  FUNC(104),FUNC(105),FUNC(106),FUNC(107),FUNC(108),FUNC(109),FUNC(110),FUNC(111),
  FUNC(112),FUNC(113),FUNC(114),FUNC(115),FUNC(116),FUNC(117),FUNC(118),FUNC(119),
  FUNC(120),FUNC(121),FUNC(122),FUNC(123),FUNC(124),FUNC(125),FUNC(126),FUNC(127),
};

void setup ()
  {
  Serial.begin (115200);
  Serial.println ();
  Serial.println ("Starting");
  
  for (int i = 0; i < 128; i++)
    Serial.println (myTable [i], 4);
  }  // end of setup

void loop () { }

It’s not particularly verbose, and now you can change any of the parameters when you compile, and adjust according to the processor (with #ifdef etc.).

If you Google “c++ loops at compile time” you may find answers that use templates, but you may find them fiddly to get working. The code above should be perfectly adequate.

It turns out it can be done, with a bit of a pre-processing trick.

Add a .h file to your project (new tab in the top RH corner) like this:

myTable.h

#if __COUNTER__ == 0
    const float myTable [ENTRIES] = {
    #include "myTable.h"
#elif __COUNTER__ < (ENTRIES * 3)
   FUNC((__COUNTER__ / 3) - 1),
    #include "myTable.h"
#else
    };  // end of myTable
#endif

This rather obscure file calls itself recursively to generate the table (calling FUNC for each entry).

Now the main file:

#define ENTRIES 128

const float AccumMax = 3;
const float aFreq = 1.2;
const float lowA = 16;
const float samplingfrequency = 1000;

#define FUNC(x) AccumMax * ((pow( aFreq, x-21 ) * lowA)/samplingfrequency)

#include "myTable.h"
 
void setup ()
  {
  Serial.begin (115200);
  Serial.println ();
  Serial.println ("Starting.");
  
  for (int i = 0; i < ENTRIES; i++)
    Serial.println (myTable [i], 4);
  }  // end of setup

void loop () { }

This uses a compiler feature, the COUNTER symbol, which the compiler adds one to, each time it is used. When it is zero, the include file creates a table. Then it recurses, and for each recursion (up to ENTRIES) it generates another table line. Then when the limit is reached it finishes off the table.

In this line:

   FUNC((__COUNTER__ / 3) - 1),

We divide by 3 because COUNTER appears 3 times in the include file, and thus goes up by 3 each time. And by the time it is used we have 3 / 3 which is 1, so to get back to a zero-relative argument we have to subtract one.


Now I’m not necessarily recommending this because for one thing it is obscure, and for another, for a larger table the compiler eventually complains:

myTable.h:6:25: error: #include nested too deeply

Wow Nick Gammon,

You are great, thank you for your input and helpful suggestions. I know see the my quest for recursiveness sends me down an obscure path. Now I can conclude I will have to resort to old fashioned copy paste for my recursive functions. As mentioned in your earlier post. I think for now this would be the most clean and understandable way of doing this and it will probably come in handy as I need to generate quite a few tables in my project.

Thank you everyone!

I don't think you can call functions when calculating constants, unless they are auto variables, which are calculated at run-time, anyway.

According to Harbison and Steele: "No constant expression may contain assignment, increment, decrement, function call or comma expressions unless they are contained within the operand of a sizeof operator."

C++ or gnu may relax this.