Archive of ‘Allgemein’ category

ESP8266 Stompbox ( Horsekick oder Finhol oder SPD::KICK ) Nachbau

Als Gitarrist und Elektroniker will man doch mal den Beat mittrampeln. Also hatte ich mir schon einige Projekte im Web angeschaut und dann Ende Oktober eine Audio-Library zum ESP8266 gefunden. Alternativen nur mit einem Piezo oder MIkrofon in einer Pappschachtel sollen auch funktionieren, – gefielen mir aber nicht.
Ein ESP8266-Development-Board gibt es für unter 10 €, der Adafruit DAC mit 3 Watt Amp hatte ich schon gekauft, – liegt auch bei 10 €.
Das OLED-Display, weitere Kleinteile wie Piezo, Taster und ein paar kleine Bauteile machen nochmal 15€. Das Holzgehäuse  bauen, bearbeiten und die Auswahl der Sounds dauert auch  länger. Als Powersupply dient eine ältere USB-Powerbank.
Wenn man alle Teile extra kaufen muss, dann rechnet sich das Projekt auf Grund von den Kosten und dem Aufwand aus meiner Sicht nicht. Ich hatte aber alle Teile herumliegen und wollte es einfach mal ausprobieren.

So sah die erste Version aus, die dann aber später in 2 Teile durchgetrennt wurde. Somit konnten dann die Bewegungen der Ferse und somit die Geräusche und Fehltrigger minimiert werden.
Die Basis bildet ein 3-Schicht Holz ca. 28 x 14cm. Unter der Unterlegscheibe befindet sich ein Hohlraum für den ESP8266 und den Piezo. Das OLED-Display ist leicht versetzt eingebaut. Rechts bzw. hier dann oben befindet sich in einer Einbuchtung ein Taster zur Soundwahl und links in der gegenüberliegenden Einbuchtung die Klinkenbuchse.

Hman-Stompbox

Halbfertige Alternativen zum ESP8266 könnten auch Raspi-Projekte wie Samplerbox oder fertige Platinen wie Wavetrigger von Robertronics sein. Beide bieten aber keinen Anschluss eines Piezos!
Raspi-Projekte könnten final noch teurer werden, denn der Zeitaufwand zur Einrichtung von Linux könnte größer ausfallen.

Als fertige Lösung gefiel mir das Ortega Horsekick Pro  ca. 170€ und vom Datenblatt und den Sounds her das Roland Boss SDP::Kick oder SDP::Wave für über 200€.

Zurück zum “selbermachen”.

Zur Ausgabe der Sounds verwende ich die fertige Audio-Library von Earle F. Philhower, III
https://github.com/earlephilhower/ESP8266Audio

Das ZIP muss entpackt werden und dann nach /Arduino/libraries/ verschoben werden.

Die Anschaltung des DACs and den ESP8266 erfolgte wie in https://github.com/bbx10/SFX-web-trigger. Der DAC ist das “Adafruit I2S 3W Class D Amplifier Breakout – MAX98357A”.

Der Lautsprecher-Ausgang des DAC geht bei mir auf die beiden äußeren Enden eines 50kOhm-Trimmer, an dem dann der Mittelpin eines 6.3mm Klinkenbuchse über einen weiteren Widerstand hängt. Die Masse der Buchse ist auf einen “Aussenpin” des Trimmers gelegt. Nachträglich habe ich zwischen den Mittelabgriff des Trimmer und “+” der Klinkenbuchse noch einen Widerstand eingebaut … ca. 10kOhm und einen Kondensator zur Entkopplung von Gleichspannungen, – also in Reihe mit dem Widerstand.

Nach dem Zusammenbau von DAC, ESP8266, einigen Kondensatoren zur Spannungsstabilisierung und dem PIEZO fehlte nur noch die Abstimmung der Empfindlichkeit, denn der Beat soll sowohl mit sehr festen Fußwerk als auch Sportschuhen oder auch ohne Schuhe nur mit Socken funktionieren.

Nach zwei frustrierenden Abenden mit Tests verschiedener Einstellungen hatte ich dann ein einfaches Testscript gefunden und dieses funktionierte auf Anhieb ausreichend gut. Es  bildet nun die Grundlage für das eigene Stompbox-Script. Statt einen MIDI-Sound zu triggern, wird ein Sample aus dem “ProgMem” des ESP8266 ausgegeben.

Vorlage für das Testscript:

https://github.com/RyoKosaka/drums/blob/master/arduino/piezo_peak_test_MIDI/piezo_peak_test_MIDI.ino

Die Samples, die im “ProgMem” abgelegt werden, sollten unterschiedlich sein, so dass ich bei den nächsten Sessions die besten Sounds auswählen und die “schlechten” gegen andere tauschen kann.
Also habe ich in meiner Sample-Sammlung und Synths nach Percussion und Kickdrum-Samples gesucht. Diese gekürzt, auf Mono und 16 Bit gesetzt, – 44.1kHz.

Earle Philhower erklärt ausreichend gut, wie man die 16Bit-Wav-Files einfach in HEX-Files konvertrieren kann, um sie in seinen Libraries als “Audio-Source-ProgMem” zu verwenden. Ich hatte dazu aber eine eigene Javascript-Webpage gebaut, die mir die Sounds in h-Files convertiert. Die WAV-Files müssen als HEX-Files vorliegen.
Die Sound-hex-Files sehen dann etwas so aus:

const unsigned char cajonbass[] PROGMEM = {0x52,0x49,0x46,0x46,0x1a,0x6c,0x00,0x00,0x57,0x41,0x56,0x45,0x66,0x6d,0x74,0x20
,0x10,0x00,0x00,0x00,0x01,0x00,0x01,0x00,0x44,0xac,0x00,0x00,0x88,0x58,0x01,0x00....
};

Ein OLED128x64Pixel (grüne Fahne) (von Amazon) wurde an den ESP8266-Pins “D1″ / “D2″ angeschaltet., an “D3″ liegt ein Taster, wenn er geschlossen ist, zieht er den Pin D3 dann gegen Masse um die Sounds zu wechseln.

Final passen 1 MByte in das System. Ich konnte damit ca. 20 sehr kurze Sounds laden.

Die Library für das OLED-Display:
https://github.com/squix78/esp8266-oled-ssd1306
Diese wird aber innerhalb der Arduino IDE zur Installation angeboten und nennt sich dort:
“ESP8266 and ESP32 OLED Driver for SSD1306 Display by Daniel Eichhorn, Fabrive Weinberg..:”

Urspünglich war statt des Tasters ein Rotary Encoder und ein kompelexeres Menü geplant. Auch die Darstellung von kleinen Icons zu den Instrumenten habe ich wieder verworfen, denn diese verbrauchten auch zusätzlichen RAM.

Eine Idee wäre die Auslagerung der Samples in externen Storage.
Die Umwandlung der Samples in andere komprimierte Formate würden zusätzliche Zeit zur Dekodierung und somit zu Latenzen beim Triggern führen.

Das Holzgehäuse besteht nun aus 2 Teilen, einem Teil mit der Elektronik und dem Piezo und einem Stück Holz. Beide Teile sind miteinander über Gummistücke verbunden und ergeben die Auflagefläche für einen Fuß. Der passive Teil liegt unter der Ferse und der aktive Teil mit dem Piezo kann sicher mit dem Fuß getrigggert werden.

Unten drunter gibt es jeweils Gummifüße gegen das Verrutschen. (Bilder folgen)
In einer ersten Version hatte ich nur eine große Holzplatte  eingeplant, musste diese Version aber verwerfen, denn schon die Bewegung des Fußes auf der Platte sorgte für Fehltrigger oder Doppeltrigger beim Runtertreten und beim Abheben des Fußes.

Technisch machen es sich die Hersteller einfach und liefern nur das aktive Teil, auf das man treten soll. Ergonomisch ist das aber nicht, denn man muss zum niedertreten den Fuß weit anheben.

Hier das vorläufige Arduino-Script:

#include <Arduino.h>
#include <ESP8266WiFi.h>
#include "AudioFileSourcePROGMEM.h"
#include "AudioGeneratorWAV.h"
#include "AudioOutputI2SDAC.h"

#include <Wire.h>  
#include "SSD1306.h"

// WAV-Files
// WAV-Files, MONO 44.1 KBIT/s 16Bit
#include "fatbass.h"
#include "softkick.h"
#include "espkik03.h"
// #include "espkik04.h"
#include "cajonbass.h"
#include "espkik06.h"
#include "espkik07.h"
#include "espkik08.h"
#include "espkik09.h"
#include "espkik10.h"
#include "espkik11.h"
#include "espkik12.h"
#include "espkik13.h"
#include "espkik14.h"
#include "espkik15.h"
// #include "espkik16.h"
#include "espkik17.h"
#include "espkik18.h"
#include "espkik19.h"
#include "espkik20.h" 
#include "espkik22.h"
#include "ride1.h"
// #include "espkik28.h"

AudioGeneratorWAV *wav;
AudioFileSourcePROGMEM *file;
AudioOutputI2SDAC *out;

unsigned short buttonState = 0; // Selectbutton for the sounds
unsigned short oldButtonState = 1;
boolean piezo = false;
int maxPiezo = 400;
int gaindevider = 380;

unsigned short s = 0;
unsigned short s_old = 20; // Sample-ID


const char *samplenames1[] ={"0 Fat",
     " 1 Soft    " , " 2 Cajon  "
   , " 3 Rock   " , " 4 Ride  "
   , " 5 Cajon  " , " 6 Arabic"
   , " 7 Acoust " , " 8 Acoust"
   , " 9 R908   " , "10 R809  "
   
   , "11 Tambo- ", "12 Christ."
   , "13 Cabasa ", "14 Guiro  "
   , "15 Rattle ", "16 Rattle",
   , "16 Cow    ", "17 Claves "
   , "18 Clap   ", "19 Side   "
   , "20 Hihat  ", "21 Ride   "
   
  };

const char *samplenames2[] ={"Drum",
     "    Kick",  "    Bass"
   , "    Kick",  "    Cymbal"
   , "    Bass",  "    Bass"
   , "    Stomp", "    Stomp"
   , "    Synth", "    Synth"
   , "    Latin",  "    Latin"
   , "rine Man",  "    Bells"
   , "    Latin", "    Latin" 

   , "    Bell",  "         "
   , "    Clap",  "    Stick"
   , "   Closed","    Cymbal"

  };  


unsigned short samplecount = 21; // Anzahl der Samples für den Select-Button
SSD1306  display(0x3c, 5, 4); //Labeled D1, D2
const int buttonPin = 0; // Labeled D3, Pin is high by default, button between this pin and GND to switch the sounds


void setup() {
  WiFi.forceSleepBegin();
  display.init();
  // display.flipScreenVertically();
  display.setContrast(255);

  display.setTextAlignment(TEXT_ALIGN_LEFT);
  display.setFont(ArialMT_Plain_24);
  display.drawStringMaxWidth(0 , 0 , 128, " Heinemann");
  display.drawStringMaxWidth(0 , 24 , 128,"  Stomper");
  // display.drawXbm(20, 30, bassdrum_width, bassdrum_height, bassdrum_bits);
  display.display();

  
  // pinMode(BUILTIN_LED, OUTPUT);
  Serial.begin(115200);
  delay(3000);
  
  file = new AudioFileSourcePROGMEM( fatbass, sizeof(fatbass) ); // Short Demosound after Booting
  out = new AudioOutputI2SDAC();
  out->SetGain(0.02);
  wav = new AudioGeneratorWAV();
  wav->begin(file, out);
  
  pinMode( buttonPin, INPUT); // GPIO 0 == D03 on ESP8266 !!

}


void loop() {
  
  if ( s != s_old ) {
    if (s >= samplecount) {
      s=1;
    }
    s_old = s;
    display.clear();
    display.setTextAlignment(TEXT_ALIGN_LEFT);
    display.setFont(ArialMT_Plain_24);
    display.drawStringMaxWidth(0 , 0 , 128, samplenames1[s]);
    display.drawStringMaxWidth(0 , 24 , 128, samplenames2[s] ); // + (String) s);
    display.display();
  } 
  
  int sensorValue = analogRead(A0);
  int MAX;

  if (sensorValue > 20 &&  piezo == false) {
    int peak1 = analogRead(A0);
    MAX = peak1;
    delay(1);
    int peak2 = analogRead(A0);
    if (peak2 > MAX) {
      MAX = peak2;
    }
    // delay(1); // absichtlich deaktiviert!!
    int peak3 = analogRead(A0);
    if (peak3 > MAX) {
      MAX = peak3;
    }
    delay(1);
    int peak4 = analogRead(A0);
    if (peak4 > MAX) {
      MAX = peak4;
    }
   
    delay(1);
    int peak5 = analogRead(A0);
    if (peak5 > MAX) {
      MAX = peak5;
    }
    // delay(1); // absichtlich deaktiviert !!
    int peak6 = analogRead(A0);
    if (peak6 > MAX) {
      MAX = peak6;
    }
    if(MAX >= maxPiezo){
      MAX = maxPiezo;
    }

//     MAX = map(MAX, 10, maxPiezo, 1, 127); // entfaellt bei mir

    if(MAX <= 1){
      MAX = 1;
    }

    midiNoteOn( MAX );
    Serial.println( MAX);
    piezo = true;

    // teh next block could be replaced by delay(30); or anything similar...
    delay(1); //mask time
    Serial.println( 0);
    delay(1); //mask time
    Serial.println( 0 );
    delay(1); //mask time
    Serial.println( 0 );
    delay(1); //mask time
    Serial.println( 0 );
    delay(1); //mask time
    Serial.println( 0 );
    delay(1); //mask time
    Serial.println( 0 );
    delay(1); //mask time
    Serial.println( 0 );
    delay(1); //mask time
    Serial.println( 0 );
    delay(1); //mask time
    Serial.println( 0 );
    delay(1); //mask time
    Serial.println( 0 );
    delay(1); //mask time
    Serial.println( 0 );
    delay(1); //mask time
    Serial.println( 0 );
    delay(1); //mask time
    Serial.println( 0 );
    delay(1); //mask time
    Serial.println( 0 );
    delay(1); //mask time
    Serial.println( 0 );
    delay(1); //mask time
    Serial.println( 0 );
    delay(1); //mask time
    Serial.println( 0 );
    delay(1); //mask time
    Serial.println( 0 );
    delay(1); //mask time
    Serial.println( 0 );
    delay(1); //mask time
  }
  if (sensorValue <= 0 && piezo == true) {
    piezo = false;
  }

  
  buttonState = digitalRead(buttonPin);
  if ( buttonState == LOW &&  oldButtonState == HIGH ) {
    oldButtonState = buttonState;  
    s = s +1;    
    oldButtonState = buttonState;  
    delay(50); // debounce
  } else {
    oldButtonState = buttonState;  
  }

  if (wav->isRunning()) {
    if (!wav->loop()) { 
      wav->stop(); // wenn nicht mehr richtig looped dann stoppen
    }
  }  
}

void midiNoteOn( int midiVelocity){
  if (midiVelocity > 0) {
  switch (s) {
      case 0:
        file = new AudioFileSourcePROGMEM( fatbass, sizeof(fatbass) ); 
        break;
      case 1:
        file = new AudioFileSourcePROGMEM( softkick, sizeof(softkick) );
        break;
      case 2:
        file = new AudioFileSourcePROGMEM( softkick, sizeof(softkick) );
        break;
      case 3:
        file = new AudioFileSourcePROGMEM( espkik03, sizeof(espkik03) );
        break;

       case 4:
         file = new AudioFileSourcePROGMEM( ride1, sizeof(ride1) );
         break;
      case 5:
        file = new AudioFileSourcePROGMEM( cajonbass, sizeof(cajonbass) );
        break;
      case 6:
        file = new AudioFileSourcePROGMEM( espkik06, sizeof(espkik06) );
        break;

      case 7:
        file = new AudioFileSourcePROGMEM( espkik07, sizeof(espkik07) );
        break;
      case 8:
        file = new AudioFileSourcePROGMEM( espkik08, sizeof(espkik08) );
        break;
      case 9:
        file = new AudioFileSourcePROGMEM( espkik09, sizeof(espkik09) );
        break;
      case 10:
        file = new AudioFileSourcePROGMEM( espkik10, sizeof(espkik10) );
        break;
      case 11:
        file = new AudioFileSourcePROGMEM( espkik11, sizeof(espkik11) );
        break;
      case 12:
        file = new AudioFileSourcePROGMEM( espkik12, sizeof(espkik12) );
        break;
      case 13:
        file = new AudioFileSourcePROGMEM( espkik13, sizeof(espkik13) );
        break;
      case 14:
        file = new AudioFileSourcePROGMEM( espkik14, sizeof(espkik14) );
        break;
      case 15:
        file = new AudioFileSourcePROGMEM( espkik15, sizeof(espkik15) );
        break;
     case 16: // the same as 15
        file = new AudioFileSourcePROGMEM( espkik15, sizeof(espkik15) );
        break;

       case 17:
        file = new AudioFileSourcePROGMEM( espkik17, sizeof(espkik17) );
        break;
      case 18:
        file = new AudioFileSourcePROGMEM( espkik18, sizeof(espkik18) );
        break;
      case 19:
        file = new AudioFileSourcePROGMEM( espkik19, sizeof(espkik19) );
        break;
      case 20:
        file = new AudioFileSourcePROGMEM( espkik20, sizeof(espkik20) );
        break;
      case 21:
        file = new AudioFileSourcePROGMEM( espkik22, sizeof(espkik22) );
        break;

      default:
        file = new AudioFileSourcePROGMEM( fatbass, sizeof(fatbass) ); 
        s = 1;  
      }
        
    // file = new AudioFileSourcePROGMEM(  );
    // out = new AudioOutputI2SDAC();

    // eigentlich p statt oldPiezoVal
    out->SetGain( 0.05 +  (float) midiVelocity/gaindevider ); // 0.8(float) p/130
    
    if (wav->isRunning()) {
      wav->stop(); // wenn nicht mehr richtig looped dann stoppen
    }
    wav->begin(file, out);
  }
}

Die lange Kette von Seriel.println ist ganz praktisch um die Ausgabe per Serial-Plotter zu ermöglichen. Die Sounds hatte ich Anfangs nur durchnumeriert, werde das aber ändern und sprechende Namen verwenden.

Die hex-files liegen im Ardino-Projektordner und nicht in Unterverzeichnissen. Man muss hier auch keinen Tricks zum Upload der Files anwenden.

Mit der Fuktion “out->SetGain und der Variablen “gaindevider” kann man experimentieren und somit die “Velocity” oder Anschlagempfindlichkeit verändern.

Phonegap – Cordova 2017 Teil 6: Scrolling im IPhone-Emulator und Font-Awesome

Scrolling

Im IPhoen Emulator lassen sich die pages nicht scrollen, – im Gegentest im richtigen IPhone zeigt, dass sie sich auf dem realen IPhone doch scrollen lassen.  Merkwürdig aber erstmal kein Hindernis.
Nach einigen Test mit dem Simulator habe ich festgestellt, dass Scrollen auch im Emulator funktioniert. Man muss nur (more…)

Phonegap – Cordova 2017 Teil 5: Javascript Alert funktioniert nicht

Der normale Alert funktioniert leider nicht. Als Programmierer verwendet man einen Debugger oder gibt Logs irgendwo aus und wenn es garnicht anders geht, dann verwendet man eben „alert“.
In Cordova gibt es ein Plugin für Dialoge, welches installiert werden muss.
cordova plugin add cordova-plugin-dialogs
Der zugehörige Code sieht wie folgt aus:

(more…)

Phonegap – Cordova 2017 Teil 4: Usersettings innerhalb der App sichern

Settings, – irgendwo muss der User ja seine Account-Daten für den Zugriff auf diese Tools sichern.

Wie sichert man Daten im Browser und funktioniert das auch noch in Cordova?
Die Maske war dazu schnell erstellt und dann um diese Accordionpane aus JQuery-Mobile erweitert.
Page mit Usersettings

Hier der Code:

(more…)

Phonegap – Cordova 2017 Teil1

Phonegap als Entwicklungsplattform für Smartphone-APPs hatte ich schonmal in 2014 getestet und nicht weiter verfolgt, denn so eine ganz tolle Idee zu einer APP hatte ich einfach nicht.
Ende 2016/ Januar 2017 hatte ich dann Phonegap/Cordova und xCode neu installiert.
Folgende Punkte habe ich installiert:

  • XCODE
  • Cordova via Termial:
    sudo npm install -g cordova
  • Codova/Phonegap Desktop App via Download-Package für MacOSX

Ein etwas älteres Video zu dem Thema findet in dieser englischen Video-Serie:
https://www.youtube.com/watch?v=L7KmIjFvHVw

So legt man eine erste App an
Dann habe ich unter /Documents einen neunen Ordner via Finder erzeugt und dorthin gewechselt

(more…)

SNMP-Simulator

SevOne garantiert eine Zertifizierung von neuen SNMP-Variablen innerhalb von 14 Tagen bzw. 10 Manntagen, – gehört bei denen zum Wartungsvertrag und erfolgt ohne Zusatzkosten.

Nun will natürlich ab und an auch mal selsbt noch schneller etwas selbst zertifizieren. Das geht bei SevOne relativ einfach über das GUI, – die vorhandenen Device-Certifications stehen als Beispiele zur Verfügung.

Wenn man nun ein Device zertifizieren möchte, auf das man gerade selbst keine Zugriff hat, nutzt man einen SMMP-Simulator und zieht von dem originalen Device einen SNMPWalk.
SNMP-Simulatoren kosten meist Geld. Zuerst dachte ich, dass ich mir etwas mittels Net-SNMP selbst bauen müsste.
Im Web habe ich dann aber
http://snmpsim.sourceforge.net/sharing-snapshots.html
gefunden.

Danke an die Programmierer!!!

Oracle – Passwort Reset

Problemdarstellung
Hat man das passwort der Datenbank dann doch vergessen… wie kommt man wieder dran?
Unter Windows einloggen. Man muss Mitglied der Gruppen Administrators oder der ORA_DBA sein.

Danach:
sqlplus /nolog
connect / as sysdba

Nun ist man ohne Passwort connected und kann Passwörter setzen
ALTER USER username IDENTIFIED BY new_password;

Pollin WDC2704 Display am Arduino im 4 Bit-Mode

Hallo zusammen, da ich nun selbst das Problem lösen konnte, hier die Anleitung für die Nachwelt.
Bei Pollin gab es mal das WDC2740 Display preiswert zu kaufen.
Eine einfache Ansteuerung des Displays über die LCDLib und 4 Bit scheiterte im ersten Anlauf.

Lösung: Das Display ist intern 2 Displays , die Anschlussleitungen müssen sehr kurz gehalten werden, Datenleitungen und RS über 100Ohm entkoppeln, Initialisierung als 40×2-Display, obwohl nur 27×2 sichtbar sind….. viele Stolperfallen eben.

Hier die Beschaltung:

LCD / Arduino

R/W auf Masse direkt am Display
LCD RS über 100R auf Arduino D13
LCD ENA2 auf Arduino D12
LCD ENA1 auf Arduino D11
LCD D07 über 100R auf Arduino D10
LCD D06 über 100R auf Ardiono D09
LCD D05 über 100R auf Arduino D08
LCD D04 über 100R auf Ardiono D07

Ansteuerung dann:

#include <LiquidCrystal.h>
// we need 2 LCD-Instances
LiquidCrystal lcd1(13, 11, 7,8,9,10);
LiquidCrystal lcd2(13, 12, 7,8,9,10);

void setup() {
// set up the LCD’s number of columns and rows:
// Internally they are 40×2 controlers, but the physical display is 27×2
lcd1.begin(40, 2);
lcd2.begin(40, 2);
// Print a message to the LCD.
delay(1000);
lcd1.print(“LCD1 Hello World”);
delay(2);
lcd2.print(“LCD2 Hello World, too”);
delay(2);
}

void loop() {
// set the cursor to column 0, line 1
// (note: line 1 is the second row, since counting begins with 0):
lcd1.setCursor(0, 1);
// print the number of seconds since reset:
lcd1.print(“LCD1 ” + String (millis()/1000));

lcd2.setCursor(0, 1);
lcd2.print(“LCD2 ” + String (millis()/1000) );
delay(20);
}