Record Button State und replay das Array

Hallo zusammen,

ich hänge aktuell bei einem simplen(?) Punkt in meinem Code.
Kurze Erklärung: Es soll am Ende ein Art ArcadePiano werden, wo ich Töne mit dem Buzzer aufnehmen kann (die werden noch hinterlegt), nochmal anhören kann und dann an eine weitere Person schicken kann.

Soweit kommen auch die Button States bei mir im seriellen Monitor an, nun stecke ich fest, wie ich die angeklickten Buttons States in ein Array speichern kann und mir das wiedergeben lassen kann.

Vielen Dank im Voraus :slight_smile:

Hier mein Code:

int recordToneArray[10];
int recordCount = 0;

// Ton-Buttons: C,D,E,F,G,A,B
const int buttonToneLength = 7;
int buttonTones[buttonToneLength] = {4, 5, 6, 7, 8, 9, 10};
int buttonTonesMode[buttonToneLength] = {HIGH, HIGH, HIGH, HIGH, HIGH, HIGH, HIGH};
int buttonTonesModePrev[buttonToneLength] = {HIGH, HIGH, HIGH, HIGH, HIGH, HIGH, HIGH};
int buttonPlay = 2;

int buttonRecord = 12;
int buttonRecordPrev = 0;

int startRecord = 0;

boolean playMode = digitalRead(buttonPlay);

void setup() {
  // Serial Monitor starten
  Serial.begin(9600);

  // Button-Mode für Töne auf Input setzen
  for (int i = 0; i < buttonToneLength ; i++) {
    pinMode(buttonTones[i], INPUT_PULLUP);
  }

  // Button-Mode für Play- und Record-Button setzen
  pinMode(buttonPlay, INPUT_PULLUP);
  pinMode(buttonRecord, INPUT_PULLUP);
}




void readToneButtons() {
  buttonTonesMode[0] = digitalRead(buttonTones[0]);
  buttonTonesMode[1] = digitalRead(buttonTones[1]);
  buttonTonesMode[2] = digitalRead(buttonTones[2]);
  buttonTonesMode[3] = digitalRead(buttonTones[3]);
  buttonTonesMode[4] = digitalRead(buttonTones[4]);
  buttonTonesMode[5] = digitalRead(buttonTones[5]);
  buttonTonesMode[6] = digitalRead(buttonTones[6]);
}

void savePrevMode() {
  buttonTonesModePrev[0] = digitalRead(buttonTones[0]);
  buttonTonesModePrev[1] = digitalRead(buttonTones[1]);
  buttonTonesModePrev[2] = digitalRead(buttonTones[2]);
  buttonTonesModePrev[3] = digitalRead(buttonTones[3]);
  buttonTonesModePrev[4] = digitalRead(buttonTones[4]);
  buttonTonesModePrev[5] = digitalRead(buttonTones[5]);
  buttonTonesModePrev[6] = digitalRead(buttonTones[6]);
}

void loop() {
  boolean recordMode = digitalRead(buttonRecord);
  boolean playMode = digitalRead(buttonPlay);

  if (recordMode == LOW && buttonRecordPrev == 0) {
    startRecord = 1;
    buttonRecordPrev = 1;
    Serial.println("GO");
  } if (recordMode == HIGH) {
    buttonRecordPrev = 0;
  }

  if (startRecord == 1) {
    Serial.println("Start record!");
    while (startRecord == 1) {
      readToneButtons();

      if ((buttonTonesMode[0] != buttonTonesModePrev[0]) && buttonTonesMode[0] == LOW) {
        Serial.println("0");
        recordCount++;
        delay(50);
        Serial.println("Pressed");
        savePrevMode();

      } else if ((buttonTonesMode[1] != buttonTonesModePrev[1]) && buttonTonesMode[1] == LOW) {
        Serial.println("1");
        recordCount++;
        delay(50);
        Serial.println("Pressed");
        savePrevMode();

      } else if ((buttonTonesMode[2] != buttonTonesModePrev[2]) && buttonTonesMode[2] == LOW) {
        Serial.println("2");
        recordCount++;
        delay(50);
        Serial.println("Pressed");
        savePrevMode();

      } else if ((buttonTonesMode[3] != buttonTonesModePrev[3]) && buttonTonesMode[3] == LOW) {
        Serial.println("3");
        recordCount++;
        delay(50);
        Serial.println("Pressed");
        savePrevMode();

      } else if ((buttonTonesMode[4] != buttonTonesModePrev[4]) && buttonTonesMode[4] == LOW) {
        Serial.println("4");
        recordCount++;
        delay(50);
        Serial.println("Pressed");
        savePrevMode();

      } else if ((buttonTonesMode[5] != buttonTonesModePrev[5]) && buttonTonesMode[5] == LOW) {
        Serial.println("5");
        recordCount++;
        delay(50);
        Serial.println("Pressed");
        savePrevMode();

      } else if ((buttonTonesMode[6] != buttonTonesModePrev[6]) && buttonTonesMode[6] == LOW) {
        Serial.println("6");
        recordCount++;
        delay(50);
        Serial.println("Pressed");
        savePrevMode();
      }

      if (recordCount == 9) {
        startRecord = 0;
        recordCount = 0;
        Serial.println("Record finished!");
      }

      boolean recordMode = digitalRead(buttonRecord);
      
      if (recordMode == LOW && buttonRecordPrev == 0) {
        startRecord = 0;
        recordCount = 0;
        buttonRecordPrev = 1;
        Serial.println("Record finished!");
        
      } else if (recordMode == HIGH)  {
        buttonRecordPrev = 0;
      }
    }
  }
}

void showArray() {
  for (int i= 0; i <10; i++) {
    if (playMode == LOW && buttonPlay == 0) {
    Serial.print("Hallo");
  }
  Serial.println();
  }
}


void playback() {
}```

Im englischen Teil des Forum müssen die Beiträge und Diskussionen in englischer Sprache verfasst werden. Deswegen wurde diese Diskussion in den deutschen Teil des Forums verschoben.

mfg ein Moderator.

@teresa_kah

ich glaube der erste Schritt soll sein, die ganzen Codeduplikate rauszuwerfen.
Du hattest eh einmal schon eine For Schleife, verwende das doch konsequent, so kürzt du den Sketch schon mal um ein Drittel!

int recordToneArray[10];
int recordCount = 0;

// Ton-Buttons: C,D,E,F,G,A,B
const int buttonToneLength = 7;
const int buttonTones[buttonToneLength] = {4, 5, 6, 7, 8, 9, 10};
int buttonTonesMode[buttonToneLength] = {HIGH, HIGH, HIGH, HIGH, HIGH, HIGH, HIGH};
int buttonTonesModePrev[buttonToneLength] = {HIGH, HIGH, HIGH, HIGH, HIGH, HIGH, HIGH};
const int buttonPlay = 2;
const int buttonRecord = 12;
int buttonRecordPrev = 0;
int startRecord = 0;

//boolean playMode = digitalRead(buttonPlay);  // hier macht ein digitalRead keinen Sinn
boolean playMode = false;

void setup() {
  // Serial Monitor starten
  Serial.begin(9600);

  // Button-Mode für Töne auf Input setzen
  for (int i = 0; i < buttonToneLength ; i++) {
    pinMode(buttonTones[i], INPUT_PULLUP);
  }

  // Button-Mode für Play- und Record-Button setzen
  pinMode(buttonPlay, INPUT_PULLUP);
  pinMode(buttonRecord, INPUT_PULLUP);
}

void readToneButtons() {
  for (int i = 0; i < buttonToneLength ; i++)
    buttonTonesMode[i] = digitalRead(buttonTones[i]);
}

void savePrevMode() {
  for (int i = 0; i < buttonToneLength ; i++)
    buttonTonesModePrev[i] = digitalRead(buttonTones[i]);
}

void loop() {
  boolean recordMode = digitalRead(buttonRecord);
  boolean playMode = digitalRead(buttonPlay);

  if (recordMode == LOW && buttonRecordPrev == 0) {
    startRecord = 1;
    buttonRecordPrev = 1;
    Serial.println("GO");
  }
  if (recordMode == HIGH) {
    buttonRecordPrev = 0;
  }

  if (startRecord == 1) {
    Serial.println("Start record!");
    while (startRecord == 1) {
      readToneButtons();

      for (int i = 0; i < buttonToneLength ; i++) {
        if ((buttonTonesMode[i] != buttonTonesModePrev[i]) && buttonTonesMode[i] == LOW) {
          Serial.print("i");
          recordCount++;
          delay(50);
          Serial.println(" Pressed");
          savePrevMode();
          break; // aus for ausbrechen. vorher hattest auch die else if Konstrukt
        }
      }
      if (recordCount == 9) {
        startRecord = 0;
        recordCount = 0;
        Serial.println("Record finished!");
      }

      boolean recordMode = digitalRead(buttonRecord);

      if (recordMode == LOW && buttonRecordPrev == 0) {
        startRecord = 0;
        recordCount = 0;
        buttonRecordPrev = 1;
        Serial.println("Record finished!");

      } else if (recordMode == HIGH)  {
        buttonRecordPrev = 0;
      }
    }
  }
}

void showArray() {
  for (int i = 0; i < 10; i++) {
    if (playMode == LOW && buttonPlay == 0) {
      Serial.print("Hallo");
    }
    Serial.println();
  }
}

void playback() {
}

dann kann man sich das weiter ansehen.
Du hast da ein grausliches while(1) ... wie willst du da wieder rauskommen?

Wenn ich deine Angabe richtig lese möchtest du eigentlich
im Record Modus

  • 10 Tastendrücken in einem Array speichern.
  • nach der 10 Taste wieder retour in einen Wartemodus
  • mit erneutem Druck auf Record kann die Aufnahme gestoppt werden - retour in Wartemodus

Im Warte Modus

  • auf das drücken von Record oder Play warten

Im Play Modus

  • Das Array einmal abspielen.
  • danach wieder in den Warte Modus

ist das so korrekt beschrieben?

Hallo @noiasca ,

vielen Dank schon einmal für deine Antwort.

Genau also aktuell ist es so, dass ich den Record Button drücke, dann die jeweiligen Buttons und wieder Record, um dies zu beenden. Nun möchte ich die gedrückten Buttons in das Record Array speichern (mit dem zweiten Klick auf den Record Button) und bei Bedarf nochmal spielen lassen (mit dem play Button), nachdem wird noch ein weiterer Button miteingebunden, um das gespeicherte Array über ein MQTT an eine weitere Person zu schicken, damit sich die das auch abspielen lassen kann.

Nun weiß ich allerdings nicht wie ich es hinbekommen könnte, dass ich mir die gedrückten Tasten in ein Array speichern kann.

ca so kann es funktionieren:

// https://forum.arduino.cc/c/international/deutsch/47
// by noiasca

byte recordToneArray[10]; // an array to hold recorded tones
byte recordCount = 0;     // actual index of recorded tone
size_t noOfTones = sizeof(recordToneArray) / sizeof(recordToneArray[0]); // the maximal storage of record tones

// Ton-Buttons: C,D,E,F,G,A,B
constexpr byte buttonToneLength = 7;
constexpr byte buttonTones[buttonToneLength] = {4, 5, 6, 7, 8, 9, 10};
constexpr byte buttonPlay = 2;
constexpr byte buttonRecord = 12;
//constexpr byte buttonTones[buttonToneLength] = {A0, A1, 6, 7, 8, 9, 10};
//constexpr byte buttonPlay = A2;
//constexpr byte buttonRecord = A3;

uint32_t buttonTonesTime[buttonToneLength];
byte buttonTonesState[buttonToneLength] = {HIGH, HIGH, HIGH, HIGH, HIGH, HIGH, HIGH};
byte buttonTonesPrev[buttonToneLength] = {HIGH, HIGH, HIGH, HIGH, HIGH, HIGH, HIGH};

constexpr byte debounceDelay = 50;  // time to debounce the button in ms

enum class State {Idle, Record, Play} state;

void setup() {
  Serial.begin(9600);
  // Button-Mode setzen
  for (int i = 0; i < buttonToneLength ; i++)
  {
    pinMode(buttonTones[i], INPUT_PULLUP);
  }
  pinMode(buttonPlay, INPUT_PULLUP);
  pinMode(buttonRecord, INPUT_PULLUP);
}

void loop()
{
  switch (state)
  {
    case State::Idle :
      if (digitalRead(buttonRecord) == LOW) {
        Serial.println(F("start recording"));
        recordCount = 0; // reset record
        state = State::Record;
      }
      if (digitalRead(buttonPlay) == LOW)
      {
        Serial.println(F("start playing"));
        state = State::Play;
      }
      break;
    case State::Record :
      doRecord();
      if (recordCount >= noOfTones)
      {
        Serial.println(F("recording ended"));
        state = State::Idle;
      }
      break;
    case State::Play :
      doPlayback();
      state = State::Idle;
      break;
  }
}

void doRecord()  // non blocking
{
  for (int i = 0; i < buttonToneLength ; i++) {
    if (buttonClick(i))
    {
      Serial.print(F("save button ")); Serial.print(i);
      Serial.print(F(" as note ")); Serial.println(recordCount);
      recordToneArray[recordCount] = i;
      recordCount++;
      break;
    }
  }
}

bool buttonClick(byte i)
{
  bool result = false;
  int reading = digitalRead(buttonTones[i]);
  if (reading != buttonTonesPrev[i])
  {
    buttonTonesTime[i] = millis();
  }
  if (millis() - buttonTonesTime[i] > debounceDelay)
  {
    if (reading != buttonTonesState[i])
    {
      buttonTonesState[i] = reading;
      if (buttonTonesState[i] == LOW) result = true;
    }
  }
  buttonTonesPrev[i] = reading;
  return result;
}

void doPlayback()   // blocking
{
  for (size_t i = 0; i < noOfTones; i++) {
    Serial.print(recordToneArray[i]); Serial.print(" ");
    // "beep"
    delay(500); // dirty delay to hear the beep
  }
  Serial.println();
}

der Ablauf ist jetzt so wie von mir in #3 beschrieben mit fixer länge 10.
bräuchte halt ein paar Änderungen um mit Record die Aufnahme stoppen zu können, aber das sollte eigentlich klar sein.
Das onClick ist das Beispiel Debounce aus der IDE. Es meldet true retour wenn der button geklickt wird.
das Abspielen ist noch blockierend, aber das kann man auch ändern. Tut aber nichts zur Sache.
Jetzt müsste man das halt noch zusammenräumen z.B. Strukturen für Variablen machen die zusammengehören.

@noiasca Vielen dank erstmal, das funktioniert super!! Wirklich eine große Hilfe :slight_smile:

Ich hätte noch eine Frage zu dem onClick, zuvor hatte ich ja alle Buttons einzeln abgefragt, was mir das hintelegen der Töne einfacher gemacht hätte (zumindest in meinem Arduino Denken).

Ist es möglich, dass ich diese einfach global deklariere und diese dann im onClick mit abfragen kann?

das verstehe ich nicht. So wie du die Buttons in Post #1 abgefragt hast,, hat macht jeder Button genau das gleiche nur ein anderer Text wird auf der Seriellen ausgegeben.
Genau das passiert in meinen Sketchen auch, nur dass es eben in einer Forschleife abgearbeitet wird und der Code nur einmal dort steht.

Was meinst du "mit Töne hinterlegen" ganz genau? Im recordToneArray sind die gedrückten Tasten=Töne enthalten.

@noiasca Ja genau das stimmt, sorry hatte vergessen die Tone Datei mit zuschicken. Habe aktuell die Töne mit #define hinterlegt und würde gerne sobald Button x gedrückt ist den Ton mit tone(Piezo..) ausgeben lassen.

Die while ist nur ein Beispiel wie es ohne record Array funktioniert hat.

Ich habe es schon versucht in dem Code zu ändern, sodass in der forSchleife der Ton mit angesprochen wird, da tritt dann das problem auf, dass der Ton dauerhaft ausgeben wird.

#define NOTE_D 294
#define NOTE_E 330
#define NOTE_F 349
#define NOTE_G 392
#define NOTE_A 440
#define NOTE_B 493

const int PIEZO = 11;

const int BUTTON_E = 8;

 while(digitalRead(BUTTON_E) == ACTIVATED)
  {
    tone(PIEZO,NOTE_E);
    digitalWrite(LED,HIGH);
  }

da macht man sich einfach ein array mit den frequenzen und spielt die jeweilige Index Position ab.

außerdem fehlt jetzt das C :wink:

edit gleich mehrere Schritte

  • Variablen für die Buttons als Klasse angelegt
  • ein paar Methoden
  • die Aufnahme kann nun auch vor 10 beendet werden (war nur ein OR im If)
  • Frequenzen ausgeben
// https://forum.arduino.cc/c/international/deutsch/47
// by noiasca

byte recordToneArray[10]; // an array to hold recorded tones
byte recordCount = 0;     // actual index of recorded tone
size_t noOfTones = sizeof(recordToneArray) / sizeof(recordToneArray[0]); // the maximal storage of record tones

class Button {
  protected:
    const byte pin;                       // the GPIO
    uint32_t time = 0;                    // time
    uint32_t state = HIGH;                // the debounced state
    uint32_t prev = HIGH;                 // the previous state
    static const byte debounceDelay = 50; // one for all

  public:
    Button(byte pin) : pin (pin) {}
    
    void begin()
    {
      pinMode(pin, INPUT_PULLUP);
    }

    bool click()
    {
      bool result = false;
      byte reading = digitalRead(pin);
      if (reading != prev)
      {
        time = millis();
      }
      if (millis() - time > debounceDelay)
      {
        if (reading != state)
        {
          state = reading;
          if (state == LOW) result = true;
        }
      }
      prev = reading;
      return result;
    }
};

// Ton-Buttons:      C, D, E, F, G, A, B

Button buttonTone[] {4, 5, 6, 7, 8, 9, 10};
Button buttonPlay   {2};
Button buttonRecord {12};
/*
  Button buttonTone[] {A0, A1, 6, 7, 8, 9, 10};
  Button buttonPlay   {A2};
  Button buttonRecord {A3};
*/
constexpr byte buttonToneLength = sizeof(buttonTone) / sizeof(buttonTone[0]);
enum class State {Idle, Record, Play} state;

//                                      C  D    E    F    G    A    B                                       
const uint16_t freq[buttonToneLength] {42, 294, 330, 349, 392, 440, 493}; // C richtig stellen!

void setup() {
  Serial.begin(9600);
  // Button-Mode setzen
  for (auto &i : buttonTone) i.begin();
  buttonPlay.begin();
  buttonRecord.begin();
}

void loop()
{
  switch (state)
  {
    case State::Idle :
      if (buttonRecord.click()) {
        Serial.println(F("start recording"));
        recordCount = 0; // reset record
        state = State::Record;
      }
      if (buttonPlay.click())
      {
        Serial.println(F("start playing"));
        state = State::Play;
      }
      break;
    case State::Record :
      doRecord();
      if (recordCount >= noOfTones || buttonRecord.click())
      {
        Serial.println(F("recording ended"));
        state = State::Idle;
      }
      break;
    case State::Play :
      doPlayback();
      state = State::Idle;
      break;
  }
}

void doRecord()  // non blocking
{
  for (int i = 0; i < buttonToneLength ; i++) {
    if (buttonTone[i].click())
    {
      Serial.print(F("save button ")); Serial.print(i);
      Serial.print(F(" as no ")); Serial.println(recordCount);
      recordToneArray[recordCount] = i;
      recordCount++;
      break;
    }
  }
}

void doPlayback()   // blocking
{
  for (size_t i = 0; i < recordCount; i++) {
    Serial.print(recordToneArray[i]); Serial.print(" f="); Serial.println(freq[recordToneArray[i]]);
    // "beep"
    delay(500); // dirty delay to hear the beep
  }
  Serial.println();
}

wenn du das schon beim Tastendruck während der Aufnahme spielen willst *), dann greifst du halt analog auf die Frequenz mit

freq[i]

zu wenn im i die Nummer vom Button steht.

*) das steht streng genommen aber NICHT in der Ablaufbeschreibung. Sollten noch weitere Überraschungen auftauchen solltest du daher deine Ablaufbeschreibung vervollständigen.
Erst kommt eine Ablaufbeschreibung - DANN der Code.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.