Arduino: Indexera en samling arrays hur?

C, C++, Pascal, Assembly, Raspberry, Java, Matlab, Python, BASIC, SQL, PHP, etc.
peyron
Inlägg: 12
Blev medlem: 25 december 2014, 21:52:20

Arduino: Indexera en samling arrays hur?

Inlägg av peyron »

Jag har ett litet projekt jag jobbar på att bygga en enkel digital synth av en arduino som skall kunna spela moll och durskalorna och har sött på ett problem.

Jag har alla tonarters frekvenser som arrays enligt följande:

Kod: Markera allt

const double aMajor[16] =
  {220.00, 246.94, 277.18, 293.66, 329.63, 369.99, 415.30, 440.00, 440.00, 493.88, 554.37, 587.33, 659.25, 739.99, 830.61, 880.00};
const double bMajor[16] =
  {246.94, 277.18, 311.13, 329.63, 369.99, 415.30, 466.16, 493.88, 493.88, 554.37, 622.25, 659.25, 739.99, 830.61, 932.33, 987.77};
... osv
Sedan kommer en meny som räknar upp en int (key_par) och beroende på vilken som väljs tilldelas en en ny array Key frekvenserna från valda tonarten.

Kod: Markera allt

void assign_key(int key_par, int major_minor)
  {
    if (major_minor == 0)
      {
	switch(key_par) //assigns chosen key to the key-variable
	  {
	  case 0:
	    memcpy(key,aMajor,64);
	    tone(3,aMajor[0]);
	    Serial.println("A-dur");
	    break;
	  case 1:
	    memcpy(key,bMajor,64);
	    tone(3,bMajor[0]);
	    Serial.println("b-dur");
	    break;
	  case 2:
	    memcpy(key,cMajor,64);
	    tone(3,cMajor[0]);
	    Serial.println("c-dur");
	    break;
... osv
Som ni ser blir tilldelningen av den valda tonarten extremt mycket kod då det krävs ett case för varje tonart och det hade varit mycket smidigare om man hade kunnat indexera tonarterna på något slags matrisvis så jag kunnat lösa tilldelningen av den valda tonart med hjälp av ett heltal. Finns det något enkelt sett att göra en array av arrays eller rent av en vektor av arrays som i c++? så att jag kunnat indexera tonart och frekvens med hjälp av två heltal?

Tack på förhand
Användarvisningsbild
Icecap
Inlägg: 26612
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Re: Arduino: Indexera en samling arrays hur?

Inlägg av Icecap »

const double aMajor[16] = {bla bla};
const double bMajor[16] = {bla bla};

const double* Tones[] = {aMajor, bMajor};

Indexering:
Tones[Toneart][Underton];
kodar-holger
EF Sponsor
Inlägg: 961
Blev medlem: 26 maj 2014, 12:54:35
Ort: Karlskoga

Re: Arduino: Indexera en samling arrays hur?

Inlägg av kodar-holger »

Du behöver ju inte ha en array för varje tonart till att börja med. Det finns ju bara ett begränsat antal i varje oktav, och beroende på tonart görs ett urval av dessa. Om du bara skall ha skalor som har enkla namn kanske något i stil med

Kod: Markera allt

const double aScale[21] = {221.00, 234.14, 248.06, 262.81, ...
const int scalestart[7] = {0, 2, 3, 5, 7, 8, 10};
const int majornotepos[0] = {0, 2, 4, 5, 7, 9, 11};
...

int index =  aScale[ scalestart[keypar] + majornotepos[note] ]
P.S.
Jag envisas med att använda 442Hz-stämning. Naturligtvis borde du räkna ut en not från en annan genom att använda en stämningsparameter och ett intervall istället.
D.S.

P.P.S.
För att krångla till saker finns det tre olika moll-skalor.
D.S.
peyron
Inlägg: 12
Blev medlem: 25 december 2014, 21:52:20

Re: Arduino: Indexera en samling arrays hur?

Inlägg av peyron »

Nu bara lekman vad gäller både programering och musikteori, men du har rätt att det där ser hemskt mycket smidigare ut! Ska leka lite och se om jag får ordning på det. Annars verkar Icecaps variant fungera rätt bra för koden jag redan har skrivit. Så tack till er båda!
kodar-holger
EF Sponsor
Inlägg: 961
Blev medlem: 26 maj 2014, 12:54:35
Ort: Karlskoga

Re: Arduino: Indexera en samling arrays hur?

Inlägg av kodar-holger »

Mer musikteori om tonarter än du kan behöva finns i dem här filmerna:

http://vimeo.com/28930209
http://vimeo.com/29251187

Jag ser att jag skrivit lite fel i min kod men det ser säkert du också.

Edit: Missade att två filmer behövdes.
peyron
Inlägg: 12
Blev medlem: 25 december 2014, 21:52:20

Re: Arduino: Indexera en samling arrays hur?

Inlägg av peyron »

Jag tror jag hänger med hyffsat och har fått ihop lite kod som du gärna får kolla igenom om du orkar.

Kod: Markera allt

const double note[37] 
{220.00, 233.08, 246.94, 261.63, 277.18, 293.66, 311.13, 329.63, 349.23, 369.99, 392.00, 415.30, 440.00,
    466.16, 493.88, 523.25, 554.37, 587.33, 622.25, 659.25, 698.46, 739.99, 783.99, 830.61, 880.00, 932.33, 
    987.77, 1046.50, 1108.73, 1174.66, 1244.51, 1318.51, 1396.91, 1479.98, 1567.98, 1661.22, 1760.00};

const int major[8] {0,2,4,5,7,9,11,12};
const int natural_minor[8] {0,2,3,5,7,8,10,12};
const int melodic_minor[8] {0,2,3,5,7,9,11,12};
const int harmonic_minor[8] {0,2,3,5,7,8,11,12};
const int * scales[] {major,natural_minor,melodic_minor,harmonic_minor};
Med detta tycker jag att man borde kunna få fram en ton genom note[grundton + scales[0-4] ] där i är position i skalan man valt 0-4

Har jag förstått saker rätt?
kodar-holger
EF Sponsor
Inlägg: 961
Blev medlem: 26 maj 2014, 12:54:35
Ort: Karlskoga

Re: Arduino: Indexera en samling arrays hur?

Inlägg av kodar-holger »

Ja, jag tycker det ser rätt ut bortsett att det är för lite kommentarer. :D Bästa kombon av mitt förslag och Icecaps. Bortsett från en liten twist i melodisk moll att den är olika om man går uppåt eller neråt. Fast det är ändå lite överkurs.

Enklast är väl att lägga in en printf och prova med lite olika input. Mycket få saker slår printf-debuggning.

Nu finns det ju bara 11 grund-skalor, och om man tar med överlappet i nästa oktav 12 tonsteg i skalan. 11 + 12 borde bli 23, så du har lite överskott på toner i din note-array.

Du bör kontrollera att i är inom gränserna 0-11. Är det utanför kan du ju se till att det hamnar innanför genom att addera eller subtrahera 12 upprepade gånger. Räkna antalet och dividera värdet du får ut med 2.0 för varje addition eller multiplicera med 2.0 för varje subtraktion.

Typ:

Kod: Markera allt

//Assume we do not have to shift octave
double octaveshift = 1.0;

//If we are above the range of one octave we need to reduce indexes to avoid indexing outside the array
while (i>11)
{
  i = i-12;  //Shift down one octave
  double octaveshift=octaveshift * 2.0; //The note frequency should be doubled for each octave we shift.
}
while (i<0)
{
  i = i+12;  //Shift up one octave
  double octaveshift=octaveshift / 2.0; //The note frequency should be halved for each octave we shift.
}

//Find the note frequency for the given scale
double note = note[i + ...] * octaveshift;
Inga garantier för att det kompilerar lämnas.

Fortsatt lämplig övning är att skriva ut skalnamnen. A-dur Aiss-dur B-dur C-dur och så vidare.

Och så kan du ju prova ren stämning istället för tempererad. Något du kan dänga klassiska klaviaturinstrument på fingrarna med.

Nästa steg blir väl pitch-bend.

Edit:
Om du kör på en klassisk arduino och inte en teensy >= 3 så är flyttal kostsamt. Mycket mycket kostsamt. Både i kodstorlek och exekveringstid. Bara så du vet.
peyron
Inlägg: 12
Blev medlem: 25 december 2014, 21:52:20

Re: Arduino: Indexera en samling arrays hur?

Inlägg av peyron »

Ja just fan! Oktaven är ju alltid dubbelt så stor så den behöver ju inte finnas med i minnet, det var bra att du poängterade

Just nu har jag löst med menyer i setup() där man först väljer skala, sen väljer grundton och min meny-funktion håller reda på gränserna och efter det tilldelas en ny array som indexeras 0-7 så när man väl är inne i loop() har man bara en array med åtta toner att hålla reda på, kanske inte är så minneseffektivt men jag har planer på att trixa till ljudet genom att svänga snabbt mellan oktaver osv och då blir det väldigt pedagogiskt att inte behöva ha sådär knepiga index.

Men allt verkar fungera som det skall så stort tack för hjälpen. Här är koden i sin helhet i nuläget om du är intresserad, men ja jag borde bli bättre på att kommentera.

Kod: Markera allt

//Constants
const double note[37] 
{220.00, 233.08, 246.94, 261.63, 277.18, 293.66, 311.13, 329.63, 349.23, 369.99, 392.00, 415.30, 440.00,
    466.16, 493.88, 523.25, 554.37, 587.33, 622.25, 659.25, 698.46, 739.99, 783.99, 830.61, 880.00, 932.33, 
    987.77, 1046.50, 1108.73, 1174.66, 1244.51, 1318.51, 1396.91, 1479.98, 1567.98, 1661.22, 1760.00};

const int major[8] {0,2,4,5,7,9,11,12};
const int natural_minor[8] {0,2,3,5,7,8,10,12};
const int melodic_minor[8] {0,2,3,5,7,9,11,12};
const int harmonic_minor[8] {0,2,3,5,7,8,11,12};
const int * scales[] {major,natural_minor,melodic_minor,harmonic_minor};
const char * note_str [] {"A", "Bb", "B", "C", "Db", "D", "Eb", "E", "F", "Gb", "G"};
const char * scale_str[] {"M", "m1", "m2", "m3"};

//Function heads
void assign_scale(int root_par); //assigns play_scale with chosen root note and scale
void menu(int down_pin, int up_pin, int bound, int & menu_par); //Toggles menu_par from 0 to bound

//Global variables
double play_scale[8]; //the array used to make sounds
int state_up, state_down, last_state_up,last_state_down; //variables used in menu function
void setup()
{
  int root_note{}; //integer 0-10 that assigns root_note
  int scale_no{}; //integer 0-3 that assigns scale
  Serial.begin(9600);
  do
    {
      menu(2,3,4,scale_no);
      Serial.println(scale_str[scale_no]);
    }
  while(analogRead(5) < 100);
  delay(1000);
  do
    {
      menu(2,3,11,root_note);
      assign_scale(root_note,scale_no);
      Serial.println(note_str[root_note]);
      tone(3, play_scale[1],250);
      delay(250);
    } while(analogRead(5) < 100);
}

void loop()
{
  if(analogRead(2) > 100 && analogRead(1) < 100)
    tone(3,play_scale[0],250);
  if(analogRead(3) > 100 && analogRead(1) < 100)
    tone(3,play_scale[1],250);
  if(analogRead(4) > 100 && analogRead(1) < 100)
    tone(3,play_scale[2],250);
  if(analogRead(5) > 100 && analogRead(1) < 100)
    tone(3,play_scale[3],250);
  if(analogRead(2) > 100 && analogRead(1) > 100)
    tone(3,play_scale[4],250);
  if(analogRead(3) > 100 && analogRead(1) > 100)
    tone(3,play_scale[5],250);
  if(analogRead(4) > 100 && analogRead(1) > 100)
    tone(3,play_scale[6],250);
  if(analogRead(5) > 100 && analogRead(1) > 100)
    tone(3,play_scale[7],250);  
}
 void menu(int down_pin, int up_pin, int bound, int & menu_par)
  {
    state_up = analogRead(up_pin);
    if (state_up > 100 && last_state_up < 100)
	++menu_par;

    last_state_up = state_up;

    state_down = analogRead(down_pin);
    if (state_down > 100 && last_state_down < 100)
	--menu_par;

    last_state_down = state_down;

    if(menu_par == bound) //upper bound
      menu_par = 0;
    if(menu_par == -1) //lower bound
      menu_par = bound -1; 
  }
void assign_scale(int root_par, int scale_par)
 {
   for(int i = 0; i<8; ++i)
     {
       play_scale[i] = note[root_par + scales[scale_par][i]]; // fills major scale for chosen root note
     }
 }

Skriv svar