Forum: Compiler & IDEs Arduino Theremin


von Julia Z. (julia21)


Angehängte Dateien:

Lesenswert?

Hi,
ich bin Julia und suche Leute, die mir bei meiner Programmierung 
behilflich sein können.
Ich möchte mit dem Arduino ein Theremin bauen und habe dazu zwei 
Infrarotabstand-Sensoren benutzt.
Der eine Sensor, soll für die Tonhöhe verantwortlich sein, der andere 
soll die Lautsärke variieren.
Ich habe versucht die Signale im Programm in Midisignale zu verarbeiten. 
Diese, gehen über einen Midikonverter an meinen Computer, wo sie in ein 
Synthesizerprogramm geladen werden, wo man alle möglichen Instrumente 
einstellen kann.
Ich habe mich bei der Programmierung an folgendes Programm gehalten, 
dass ich auf der Arduino-homepage gefunden habe:

Allow a Person to Play Notes

The previous example will just play notes, no interactivity. The example 
below uses an analog input to set the pitch, and a digital input (a 
switch) to start and stop the note:

// The switch is on Arduino pin 10:
#define switchPin 10
// Middle C (MIDI note value 60) is the lowest note we'll play:
#define middleC 60
//  Indicator LED:
#define LEDpin 13

// Variables:
char note = 0;            // The MIDI note value to be played
int AnalogValue = 0;           // value from the analog input
int lastNotePlayed = 0;   // note turned on when you press the switch
int lastSwitchState = 0;  // state of the switch during previous time 
through the main loop
int currentSwitchState = 0;

void setup() {
  //  set the states of the I/O pins:
  pinMode(switchPin, INPUT);
  pinMode(LEDpin, OUTPUT);
  //  Set MIDI baud rate:
  Serial.begin(31250);
  blink(3);
}

void loop() {
  //  My potentiometer gave a range from 0 to 1023:
  AnalogValue = analogRead(0);
  //  convert to a range from 0 to 127:
  note = AnalogValue/8;
  currentSwitchState = digitalRead(switchPin);
  // Check to see that the switch is pressed:
  if (currentSwitchState == 1) {
    //  check to see that the switch wasn't pressed last time
    //  through the main loop:
    if (lastSwitchState == 0) {
      // set the note value based on the analog value, plus a couple 
octaves:
     // note = note + 60;
      // start a note playing:
      noteOn(0x90, note, 0x40);
      // save the note we played, so we can turn it off:
      lastNotePlayed = note;
      digitalWrite(LEDpin, HIGH);
    }
  }
    else {   // if the switch is not pressed:
    //  but the switch was pressed last time through the main loop:
    if (lastSwitchState == 1) {
      //  stop the last note played:
      noteOn(0x90, lastNotePlayed, 0x00);
      digitalWrite(LEDpin, LOW);
    }
}

  //  save the state of the switch for next time
  //  through the main loop:
  lastSwitchState = currentSwitchState;
}

//  plays a MIDI note.  Doesn't check to see that
//  cmd is greater than 127, or that data values are  less than 127:
void noteOn(char cmd, char data1, char data2) {
  Serial.print(cmd, BYTE);
  Serial.print(data1, BYTE);
  Serial.print(data2, BYTE);
}

// Blinks an LED 3 times
void blink(int howManyTimes) {
  int i;
  for (i=0; i< howManyTimes; i++) {
    digitalWrite(LEDpin, HIGH);
    delay(100);
    digitalWrite(LEDpin, LOW);
    delay(100);
  }
}

Play Notes

Once you're connected, sending MIDI is just a matter of sending the 
appropriate bytes. The bytes have to be sent as binary values, but you 
can format them in your code as decimal or hexadecimal values. The 
example below uses hexadecimal format for any fixed values, and a 
variable for changing values. All values are sent serially as raw binary 
values, using the BYTE modifier to Serial.print() (Many MIDI tables give 
the command values in hex, so this was done in hex for the sake of 
convenience):

// Variables:
char note = 0;            // The MIDI note value to be played

void setup() {
  //  Set MIDI baud rate:
  Serial.begin(31250);
}

void loop() {
  // play notes from F#-0 (30) to F#-5 (90):
  for (note = 30; note < 90; note ++) {
    //Note on channel 1 (0x90), some note value (note), middle velocity 
(0x45):
    noteOn(0x90, note, 0x45);
    delay(100);
    //Note on channel 1 (0x90), some note value (note), silent velocity 
(0x00):
    noteOn(0x90, note, 0x00);
    delay(100);
  }
}

//  plays a MIDI note.  Doesn't check to see that
//  cmd is greater than 127, or that data values are  less than 127:
void noteOn(char cmd, char data1, char data2) {
  Serial.print(cmd, BYTE);
  Serial.print(data1, BYTE);
  Serial.print(data2, BYTE);
}


Leider habe ich nicht das gewünschte Ergebnis erzielt. Es lassen sich 
nur fünf Töne spielen, die auch nicht besonders sauber klingen; außerdem 
hätte ich gerne einen durchgehenden Ton, habe aber stattdessen ein sich 
ständig wiederholendes Tuten. Quasi ein Tut tut tut anstatt eines 
Tuuuuuuut.
Ich habe schon viele Varianten ausprobiert und an dem Programm rum 
gefummelt, da ich aber blutige Anfängerin bin, bin ich bereits an meine 
Grenzen gestoßen und hoffe, dass sich jemand die Zeit nimmt und schaut, 
was ich vielleicht falsch gemacht habe.
Ich danke euch im Voraus.
Liebe Grüße
Julia


// The switch is on Arduino pin 10:
int note = 0;           //Tonhöhe
int sensorPin2 = 2; //Tonsensor auf Pin2
int digiData2 = 2;
int sensorPin3 = 1; //Lautstaerkesensor auf Pin1
int digiData3 = 3;
int out1 = 0;          //Lautstärke
int x = 0;              //zählvariable
int count = 0;
int digiZ = 20; //Zähler, wie wiele Werte aufsummieren
int digiT = 0; // Index für Anzahl der Werte
int digiAll = 0;  //Summe der Werte
int digiAll2 = 0;
int digiT1 = 0;
int values[] = {0,1,2,3,4,5,6,7};
int lou[]= {0x00,0x20,0x30,0x40,0x50,0x70,0x80,0x90};
int notes[] = {0,20,30,40,50,70,80,90};

void setup() {
Serial.begin(31250);
//Serial.begin(9600);
}

void loop() {
  for(x = 0 ; x <= 5; x+=1)
  {
    do
    {
      digiData2 = analogRead(sensorPin2);
      digiAll= digiAll + digiData2;
      digiT++;
    } while(digiT<digiZ);
    digiData2 = digiAll/digiZ/80;
    digiT = 0;
    digiAll = 0;
    for(count=0; count<=5; count++) {
      if (values[count] == digiData2) {
        note = notes[count];
      }
    }

    }

  for(x = 0 ; x <= 10; x+=1)
  {
    do
    {
      digiData3 = analogRead(sensorPin3); // Werte vom Sensor einlesen
      digiAll2= digiAll2 + digiData3; //Aufsummieren der Sensorwerte in 
der variablen digiAll2
      digiT1++; // Zähler hochsetzen, wie viele werte aufsummiert wurden
    } while(digiT1<digiZ); //Schauen ob Anzahl der AUfsummierten Werte 
schon die geplante Anzahl digiZ ist
    digiData3 = digiAll2/digiZ/80;
    digiT1 = 0; //Nullsetzen der Zählervariablen
    digiAll2 = 0; //Nullsetzen der Summenvariablen
    //digiData3 = digiData3/150;
    for(count=0; count<=5; count ++) {
      if (values[count] == digiData3) { // Auslesen des Lautstärkewertes 
aus der Liste lou passend zum ermittelten digiData3-Wert
        out1 = lou[count];
      }
    }
 }

  noteOn(0x90, note, out1);
  delay(100);
  noteOn(0x90, note, 0);
  delay(100);
}

void noteOn(char cmd, int data1, int data2) {
 Serial.print(cmd, BYTE);
 Serial.print(data1, BYTE);
 Serial.print(data2, BYTE);

//Serial.print(digiData2);
//Serial.println("  ");
// Serial.println(digiData21);
 //Serial.println( "        ");
//Serial.print(digiData3);
 //Serial.print("  ");
 //Serial.println(out1);
}

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

> Leider habe ich nicht das gewünschte Ergebnis erzielt.
> Es lassen sich nur fünf Töne spielen, die auch nicht
> besonders sauber klingen; außerdem hätte ich gerne einen
> durchgehenden Ton, habe aber stattdessen ein sich
> ständig wiederholendes Tuten. Quasi ein Tut tut tut anstatt eines
> Tuuuuuuut.

Das liegt an der verwendeten Tonerzeugung - hier wird ein 
MIDI-Musikinstrument angesteuert, das die Töne erzeugt. Das ist auch für 
den unsauberen Klang verantwortlich

Und hiermit

  noteOn(0x90, note, out1);
  delay(100);
  noteOn(0x90, note, 0);
  delay(100);

sagst Du Deinem Instrument, daß es einen Ton mit Laustärke out1 erzeugen 
soll, wartest eine fest vorgegebene Zeit und schaltest dann die 
Tonausgabe ab (mit Lautstärke 0).

Das kann sich dann auch nur so anhören, wie das von Dir beschriebene 
Tut-Tut-Tut.

Du solltest das Note-Off erst dann senden, wenn es eine Veränderung des 
Tones in Lautstärke oder Tonhöhe gibt.

Eine fließende Tonhöhenveränderung, wie sie zum Theremin passt, ließe 
sich mit einem pitch bender erzeugen - wie der anzusteuern ist, ist 
dem MIDI-Programmierhandbuch Deines Musikinstrumentes zu entnehmen.

von daniel d. (Gast)


Lesenswert?

Kann das vielleicht auch an der Bautrate liegen?
Ich will etwas ähnliches bauen und sende im Moment als Versuch immer nur 
eine Note im Intervall von 2000ms. Diese werden von TxD über eine Midi 
Buchse über ein Midikabel direkt zu meinen Midieingang in der Soundkarte 
übertragen.
Dabei kommen auch nicht immer alle übertragenen Noten an. Manchmal nur 
jede 5te aber mnchmal auch die 2te nicht variiert sehr.
Weiß jemand ob man mit einem Ardu in 31250 Baud senden kann?

Weil in dem Seriellen Monitor in der Ardu Software kann man diese 
Baudrate auch nicht einstellen. Ist scheinbar keine Standardrate?! Oder 
wird nicht von der Seriellenschnittstelle unterstützt? (Vermutung nur!)

Grüße Daniel

von Andreas W. (andreasw) Benutzerseite


Lesenswert?

daniel d. wrote:
> Weiß jemand ob man mit einem Ardu in 31250 Baud senden kann?
Ja, das geht. Die Arduino Boards haben ein 16MHz oder 8MHz Quarz und 
damit sind 31250 Baud ohne Fehler möglich.

Wie sieht denn deine genaue Beschaltung aus?

von daniel d. (Gast)


Lesenswert?

Hat sich erledigt. Es lag nicht an der Baudrate, sondern an den 
gesendeten Noten, denn die waren einfach zu kurz. Aber trotzdem danke!

Die Midi-Schaltung, für die die es vielleicht interessiert, ist von 
midi.org.
-> http://www.midi.org/techspecs/electrispec.php

Grüße

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.