Trivial array question.

Hello, n00b here.

I'm working on an anolog synth controller/sequencer, using the arduino to send a series of pulses to LEDs that drive photoresistors on the synth.

I've got an LCD display and TLC5940 LED driver (incredible, to someone familiar with analog electronics) all playing nice.

So I want to run the whole sequencer with one pushbutton and one potentiometer. I've got routines for twisting the pot to get various menu options on the LCD, and to scroll through all 4096 brightness values pretty easily.

Now what I want to get into is setting each beat. I'm thinking a 2d array, something like

int sequenceArray [numberOfParameters][numberOfBeats];

then, after the parameters for each beat have been entered,

numberOfBeats ++;

does this make sense to anybody?

If I can get some rudimentary code going I'll open up the synth design, pretty fun sine/triangle/square with dynamic filtering and VCAs.

Thanks in advance!

here's pretty much where I'm @:

I've got a few variables I want to encode:

int tempo = 0; int frequency = 0; int shape = 0; int sineVCA = 0; int squareFreq = 0; int squareVCA = 0; int beatNumber = 0;

I want to make an array like this:

int currentBeat [][];

but have it include {frequency, shape, sineVCA, squareFreq, squareVCA} on one side, and {beatNumber} on the other.

I'm kind of just grasping how to set this stuff up. Maybe my bullheaded wranglings will be of use to someone else.

When making two-dimensional arrays, remember that the Arduino 168 only has 1k of RAM and the 328 has 2k. Not a lot! Beware of making those arrays too big, e.g. by using 'int' when 'char' would do.

Thank you! In this case each variable will be 0-4095, for the output range of the TLC5940. the number of beats would be a smaller number, I just want to avoid presetting it, and locking down the number of steps.

so the first dimension would hold 5 (12 bit?) values, and the second dimension would contain a value set by the current beat being programmed. I could use ‘byte’ here quite easily.

I’m still getting errors setting up my array

"
error: declaration of ‘currentBeat’ as multidimensional array must have bounds for all dimensions except the first
"

but it’s still a zygote.

One does not need/have to use two dimensions:

const byte NUMBER_OF_BEATS = 4; //change to suit your needs

//this data structure uses 9 bytes as opposed to six ints which is 12. 25% saved!
typedef struct {
byte tempo : 12;
byte frequency : 12;
byte shape : 12;
byte sineVCA : 12;
byte squareFreq : 12;
byte squareVCA : 12;
} Beat;

//initialize the Beats
Beat currentBeat[NUMBER_OF_BEATS] = {
{ 1 , 440 , 0, 0, 0, 0 },
{ 1 , 880 , 0, 0, 0, 0 },
{ 1 , 220 , 0, 0, 0, 0 },
{ 1 , 440 , 0, 0, 0, 0 }
};

void setup(){
Serial.begin(9800);
}

void loop(){
//demonstrate usage
for (byte i=0; i<NUMBER_OF_BEATS; i++){
Serial.print(currentBeat*.tempo); //use the Beat at index i to access the tempo field*

  • Serial.print(" ");*
    _ Serial.print(currentBeat*.frequency); //use the Beat at index i to access the tempo field*_
    * }*
    }
    [/quote]

Wow! I don’t even know where to begin with this. I suppose I’ll pull it apart and find out what each piece does.

This is how learning happens; many thanks!!!

Okay, I’m beginning to get it:

const byte NUMBER_OF_BEATS = 4; //change to suit your needs

—Here I can run a routine to have the user twist the pot to get a number of beats? Even if I’m limited to 10-20 beats total, I’d like to be able to select measures of any length----

//this data structure uses 9 bytes as opposed to six ints which is 12. 25% saved!
typedef struct {
byte tempo : 12;
byte frequency : 12;
byte shape : 12;
byte sineVCA : 12;
byte squareFreq : 12;
byte squareVCA : 12;
} Beat;

-----This is VERY cool: from what I see, you’re naming the exact value of bits in each variable?----

//initialize the Beats
Beat currentBeat[NUMBER_OF_BEATS] = {
{ 1 , 440 , 0, 0, 0, 0 },
{ 1 , 880 , 0, 0, 0, 0 },
{ 1 , 220 , 0, 0, 0, 0 },
{ 1 , 440 , 0, 0, 0, 0 }
};

-----okay, I see what is going on here; I guess when I’m entering the parameters I reach in here and assign array values that I can copy to my to my 12 bit variables for each beat; but it’s still a little mysterious as to how it works----

void setup(){
Serial.begin(9800);
}

void loop(){
//demonstrate usage
for (byte i=0; i<NUMBER_OF_BEATS; i++){
Serial.print(currentBeat*.tempo); //use the Beat at index i to access the tempo field*

  • Serial.print(" ");*
    _ Serial.print(currentBeat*.frequency); //use the Beat at index i to access the tempo field*_
    }
    }
    -------I still definitely have to figure out a workflow for handing the data around----------

Okay, I’m beginning to get it:

const byte NUMBER_OF_BEATS = 4; //change to suit your needs

—Here I can run a routine to have the user twist the pot to get a number of beats? Even if I’m limited to 10-20 beats total, I’d like to be able to select measures of any length----

This variable determins how many Beats there can be in the currentBeat array.

//this data structure uses 9 bytes as opposed to six ints which is 12. 25% saved!
typedef struct {
byte tempo : 12;
byte frequency : 12;
byte shape : 12;
byte sineVCA : 12;
byte squareFreq : 12;
byte squareVCA : 12;
} Beat;

-----This is VERY cool: from what I see, you’re naming the exact value of bits in each variable?----

That is correct. Very handy :slight_smile: google c++ bit fields

//initialize the Beats
Beat currentBeat[NUMBER_OF_BEATS] = {
{ 1 , 440 , 0, 0, 0, 0 },
{ 1 , 880 , 0, 0, 0, 0 },
{ 1 , 220 , 0, 0, 0, 0 },
{ 1 , 440 , 0, 0, 0, 0 }
};

-----okay, I see what is going on here; I guess when I’m entering the parameters I reach in here and assign array values that I can copy to my to my 12 bit variables for each beat; but it’s still a little mysterious as to how it works----

Normally, you use ints, for example:

int arr[3] = { 1 , 2 , 3 };

The numbers 1,2 and 3 are there because they are ints right? Everything else is just part of the syntax.

The normal way to create and use structs follows this syntax:

struct TwoBytes {
  byte lowByte;
  byte highByte;
}

TwoBytes myTwoBytes = { 128 , 255 };

Now, if one wants an array with three elements you do:

TwoBytes arr[3] = { {0,0} , {128,128} , {255,255} };

As with int the {0,0}, {128,128} and {255,255} are there bacause they are TwoBytes

void loop(){
//demonstrate usage
for (byte i=0; i<NUMBER_OF_BEATS; i++){
Serial.print(currentBeat*.tempo); //use the Beat at index i to access the tempo field*

  • Serial.print(" ");*
    _ Serial.print(currentBeat*.frequency); //use the Beat at index i to access the tempo field*_
    }
    }
    -------I still definitely have to figure out a workflow for handing the data around----------[/quote]
    What is it that you want your program to do?
    It might be that the struct solution is not the best way to go, but it sure is an alternative to twodimensional int array.

So cool! I have been reading up on structs just now. I guess this is a little ambitious for a beginner programmer.

so anyway, I've been playing around with the arduino for a while, seeing how it could fit in to my synth/gadget hobby. I just built this analog synth:

http://www.youtube.com/watch?v=wZ6Mk_MnEck

and it does some fun self-sequencing. But I thought it would be really interesting to mate it with the arduino. So I'll take the synth core and set it up with photoresistors to control with the arduino.

What I had in mind was a box with a pot, a button, and an LCD display

(because I am SICK of doing all the switches and knobs by hand!!!).

the user would see a prompt to enter the parameters for the first beat. using the pot, they could scroll through the parameters, and dial in the 0-4095 step value for whatever part of the synth they were controlling.

here's sort of a flow chart:

enter parameters for beat.

(option to playback with tempo)

enter parameters for next beat.

(playback automatically plays sequence of beats, freeing pot up for tempo adjustment)

so that's it. user could stop at one beat, or 7 if they wanted to. Maybe have a few loop options, like reverse looping and stuff.

maybe if I can squeeze a little more code into it have a generative part that sort of randomizes the values and spits them out at every tempo click.

Can you verify the sizeof(Beat) as being nine bytes? Just print it to serial with Serial.println(sizeof(Beat), DEC);. I wasn't aware the avr-gcc compiler supported realigning of values larger than the pack size; that is, packing two twelve-bits into three bytes.

Hello halley

const byte NUMBER_OF_BEATS = 4; //change to suit your needs

//this data structure uses 9 bytes as opposed to six ints which is 12. 25% saved!
typedef struct _beat{
unsigned tempo : 12;
unsigned frequency : 12;
unsigned shape : 12;
unsigned sineVCA : 12;
unsigned squareFreq : 12;
unsigned squareVCA : 12;
unsigned operator(int subscript){
switch (subscript){
case 0: return tempo; break;
case 1: return frequency; break;
case 2: return shape; break;
case 3: return sineVCA; break;
case 4: return squareFreq; break;
case 5: return squareVCA; break;
}
}
} Beat;

//initialize the Beats
Beat currentBeat[NUMBER_OF_BEATS] = {
{ 1 , 440 , 0, 0, 0, 0 },
{ 1 , 880 , 0, 0, 0, 0 },
{ 1 , 220 , 0, 0, 0, 0 },
{ 1 , 440 , 0, 0, 0, 0 }
};

void setup(){
Serial.begin(9800);
Serial.println(sizeof(currentBeat[0]));
//demonstrate usage
for (byte i=0; i<NUMBER_OF_BEATS; i++){
Serial.print(currentBeat*[0]); //use the Beat at index i to access the tempo field*

  • Serial.print(" ");*
    _ Serial.println(currentBeat*[1]); //use the Beat at index i to access the tempo field*_
    * }*
    }
    void loop(){
    }
    [/quote]
    It prints 9.
    I mixed byte and unsigned [bacause I mentally think byte as soon as I think of unsigned]
    [edit]
    This sketch lets you edit the beat realtime, just to show how it can be done.
    It starts with printing
    > 1 440 0 0 0 0
    But if you send
    > 234
    It will change the currentBeatIndex to the beat at index 2, and change parameter index 3 (sineVCA) to 4.
    Then it will print
    > 1 220 0 4 0 0
    Try it:
    > //how many beats will you need to store?
    > const byte NUMBER_OF_BEATS = 4; //change to suit your needs
    >
    > //this data structure uses 9 bytes as opposed to six ints which is 12. 25% saved!
    > typedef struct {
    > unsigned tempo : 12;
    > unsigned frequency : 12;
    > unsigned shape : 12;
    > unsigned sineVCA : 12;
    > unsigned squareFreq : 12;
    > unsigned squareVCA : 12;
    > //extract the value of one of the members of this struct
    > unsigned operator[](int subscript){
    > switch (subscript){
    > case 0: return tempo; break;
    > case 1: return frequency; break;
    > case 2: return shape; break;
    > case 3: return sineVCA; break;
    > case 4: return squareFreq; break;
    > case 5: return squareVCA; break;
    > }
    > }
    > //assign a value to one of the members of this struct
    > void assign(byte subscript,int val){
    > switch (subscript){
    > case 0: tempo = val; break;
    > case 1: frequency = val; break;
    > case 2: shape = val; break;
    > case 3: sineVCA = val; break;
    > case 4: squareFreq = val; break;
    > case 5: squareVCA = val; break;
    > }
    > }
    > } Beat;
    >
    > //initialize the Beats
    > Beat currentBeat[NUMBER_OF_BEATS] = {
    > { 1 , 440 , 0, 0, 0, 0 },
    > { 1 , 880 , 0, 0, 0, 0 },
    > { 1 , 220 , 0, 0, 0, 0 },
    > { 1 , 440 , 0, 0, 0, 0 }
    > };
    >
    > byte currentBeatIndex = 0; //store the index of the current byte
    >
    >
    > void setup(){
    > Serial.begin(9800);
    > Serial.println(sizeof(currentBeat[0]));
    > }
    >
    > void loop(){
    > if (Serial.available()>0){
    > currentBeatIndex = Serial.read() - ‘0’;
    > unsigned long time = millis();
    > while (millis()<time+2000){
    > if (Serial.available()>=2){
    > currentBeat[currentBeatIndex].assign(Serial.read() - ‘0’,Serial.read() - ‘0’); //convert character to number, and use as index and value on the current Beat
    > }
    > }
    > }
    > Serial.print(currentBeat[currentBeatIndex][0]);//print using array subscript
    > Serial.print(" ");
    > Serial.print(currentBeat[currentBeatIndex][1]);
    > Serial.print(" ");
    > Serial.print(currentBeat[currentBeatIndex].shape);//print using member access, this also works
    > Serial.print(" ");
    > Serial.print(currentBeat[currentBeatIndex][3]);
    > Serial.print(" ");
    > Serial.print(currentBeat[currentBeatIndex][4]);
    > Serial.print(" ");
    > Serial.println(currentBeat[currentBeatIndex][5]);
    > delay(500);
    > }
    [/edit]

RE realtime editing: I think this will be the first step for at least getting the hardware going. I can this way send parameters from my laptop while I'm selecting the photoresistors for proper depth and response time.

Thanks a million I have a lot to work with!!!

Tonight I'll breadboard up the synth+active filters on their own 9VDC board so I can get everything in one place.

BTW: Impressive synth!

I am a musician myself, Stringed planks and drums, mostly. I noticed you'd called it dronestick. Do you play drone (metal?).

I have not made anything musical yet, closest thing would be a midi pedal for the keyboardist in my band. But I want to make an analog synth, but I've found very little resources on the net. Do you know about any good sites? I used to play synth before converting to the guitar thingys.

Again: Very cool project and build!

Thanks a lot! This synth is based on the XR2206, it generates a sine/triangle wave, and as a bonus, a square wave. I think I first looked into this IC when I was thinking about synth-sticks (yeah, I got my start playing bass in a metal/hardcore band for years, but I've always been into electronics). Paia had a design for a 2-voice synth stick that didn't work, but I found a way around it, and used that as basis for this synth.

for nonmusical synthing, and getting into a very cool (use it at any voltage, in any audio circuit!) bandpass filter; I'd start with this:

http://www.musicfromouterspace.com/analogsynth/YOUR_FIRST_SYNTH/WSG_Reborn/WEIRDSOUNDGENERATORREBORN.php

(I made a modded version here:

http://www.youtube.com/watch?v=nbnoU8nACOU )

the basic circuit is very simple and another candidate for arduino control!

for the synth I'm working on, this guy was my inspiration:

http://mypeoplepc.com/members/scottnoanh/birthofasynth/id20.html

(I didn't need it to be musical OR linear, so my life was easy...)

if, IF, I can figure out this sequencing business, I have a way to do full polyphony with 'real' tuned notes, by gating a top octave generator IC:

http://www.paia.com/manuals/docs/oz-howto-article.pdf

I figure use a serial command to multiplex groupings of notes, with 12-bit values for filtering and envelope....

Anyway, baby steps; and thanks for your help!!!

Hello again everybody!
I’ve built up a little bit of hardware on which to toy around with this whole array/struct thing…

here it is just running random strings from little bits of code like this:

#include "Tlc5940.h"

void setup()
{

  Tlc.init(0);
}


void loop()
{

 
    
   
    
    
    for (int channel = 0; channel <= 9; channel ++)
//channels 0-4 run the synth, 5-9 are eventually gonna mirror the synth controls for indicator LEDs.
    {
    randomSeed (analogRead(1));
    Tlc.set(channel, random (200));
    }
  
    Tlc.update();

    delay  (analogRead(0));
    }

I’m going to get all refreshed and relaxed and try and implement at least some hardcoded arrays or structs or however it is I can control this thing!

works great!!! thanks for the help.

32-'note' sequences:

http://www.youtube.com/watch?v=M6_TKkJrFsA

Cool!

I loved the last arpeggio pattern thingy. :D Or 'riff' as I use to call them. :)