Überraschenderweise läuft das ganz gut. Drucker installation war easy, okay der Labeldrucker macht bisschen doof, aber ansonsten bin ich sehr positiv überrascht. Hätte nicht gedacht das man mit dem Teil so gut arbeiten kann!
Druckbare Version
Überraschenderweise läuft das ganz gut. Drucker installation war easy, okay der Labeldrucker macht bisschen doof, aber ansonsten bin ich sehr positiv überrascht. Hätte nicht gedacht das man mit dem Teil so gut arbeiten kann!
ich sach ja, das Linux auf dem Raspi ist echt klasse! :rolleyes:
Ich gehe aber mal stark davon aus das sich mein Raspbian was den Desktop angeht nicht mehr viel mit deinem gemeinsam hat ^^^^^
So aber um das Projekt mal weiter zu treiben, hier jetzt mit Plot. Unten ist input, oben ist waveBuffer. Die beiden Linien in waveBuffer zeigen Start und Ende des Signals. Scheint ja ganz gut zu passen.
Einfach Enter drücken dann läuft das Programm weiter.
Code:#include <iostream>
#include <vector>
#include <fstream>
#include <string>
#include <stdio.h>
#include <limits.h>
#include <math.h>
#include <VG/openvg.h>
#include <VG/vgu.h>
#include <fontinfo.h>
#include <shapes.h>
#include "diaSound.hpp"
bool ausgabe = true;
int32_t sStart, sEnde;
void plotten(int32_t *input, int32_t *waveBuffer)
{
int width, height, i, x = 800;
float schritt = x / (float)SHRT_MAX;
char s[3];
initWindowSize(20, 20, x, 511);
init(&width, &height);
Start(width, height);
Background(0, 0, 0);
Fill(0, 255, 255, 1);
StrokeWidth(1.0);
for(i=0;i<SHRT_MAX;i++)
{
Stroke(255, 255, 255, 1.0);
Line((VGfloat) schritt*i, (VGfloat) input[i], (VGfloat) schritt*(i+1), (VGfloat) input[i+1]);
Stroke(255, 255, 0, 1.0);
Line((VGfloat) schritt*i, (VGfloat) waveBuffer[i]+256, (VGfloat) schritt*(i+1), (VGfloat) waveBuffer[i+1]+256);
}
Line((VGfloat) schritt*sStart, (VGfloat) 255+256, (VGfloat) schritt*sStart, (VGfloat) 0+256);
Line((VGfloat) schritt*sEnde, (VGfloat) 255+256, (VGfloat) schritt*sEnde, (VGfloat) 0+256);
End();
fgets(s, 2, stdin);
finish();
}
void analyse(int32_t *waveBuffer)
{
int32_t sbuf[128];
int32_t bias, minr, maxr, baseline,
signalstart, signalend;
int32_t maximum = waveBuffer[0];
int32_t minimum = waveBuffer[0];
int32_t maxpos, minpos;
int32_t i;
for(i=0;i<SHRT_MAX;i++)
{
if(waveBuffer[i] > maximum)
{
maximum = waveBuffer[i];
maxpos = i;
}
if(waveBuffer[i] < minimum)
{
minimum = waveBuffer[i];
minpos = i;
}
}
maximum = waveBuffer[0];
minimum = waveBuffer[0];
for(i=0;i<SHRT_MAX; ++i)
{
if(waveBuffer[i] > maximum)
{
maximum = waveBuffer[i];
maxpos = i;
}
if(waveBuffer[i] < minimum)
{
minimum = waveBuffer[i];
minpos = i;
}
}
// calculate baseline from last 100 waveBuffer cells:
// init vars
baseline=(waveBuffer[minpos] + waveBuffer[maxpos]) / 2; // init baseline by (min+max)/2
minr=baseline - 1;
maxr=baseline + 1;
// auto-adjust:
for(i=SHRT_MAX-100; i<SHRT_MAX; ++i)
{
// mean baseline
baseline = round((0.5*(float)waveBuffer[i] + 0.5*(float)baseline)) ;
// smoothed out max noise
if(waveBuffer[i] >= baseline) maxr = round((0.6*(float)waveBuffer[i] + 0.4*(float)maxr)) +1 ;
// smoothed out min noise
if(waveBuffer[i] <= baseline) minr = round((0.6*(float)waveBuffer[i] + 0.4*(float)minr)) -1 ;
}
bias = max(baseline-minr, maxr-baseline) +1;
// noise reduction start/end
// drop small noise
for(i=0;i<SHRT_MAX;++i)
{
if((waveBuffer[i]>baseline) && (waveBuffer[i] <= baseline + bias)) waveBuffer[i] = baseline ; // little higher value => drop to baseline
else
if((waveBuffer[i]<baseline) && (waveBuffer[i] >= baseline - bias)) waveBuffer[i] = baseline ; // little lower value => rise to baseline
}
// signalstart, signalend: threshold = bias + (bias/2)
signalstart = 0;
i = 0;
while((waveBuffer[i]<=baseline + 4 * bias/3) && (i<SHRT_MAX-1)) ++i;
signalstart = i;
if(i > 0) signalstart -= 1;
signalend=SHRT_MAX-1;
i=SHRT_MAX-1;
while((waveBuffer[i]<=baseline + + 4*bias/3) && (i>signalstart)) --i;
signalend = i;
if(i<SHRT_MAX-1) signalstart +=1;
sStart = signalstart;
sEnde = signalend;
if(ausgabe)
{
cout << "Bias: " << bias << endl;
cout << "Maximal: " << maximum << endl;
cout << "Minimal: " << minimum << endl;
cout << "Signalstart: " << signalstart << endl;
cout << "Signalende: " << signalend << endl;
}
}
int main(int argc, char *argv[])
{
fstream datei;
int32_t input[SHRT_MAX], waveBuffer[SHRT_MAX];
int32_t i;
if(argc <= 1) audioCapture(input, SHRT_MAX, "plughw:1,0", 1, 12000, 8);
else
{
datei.open(argv[1], ios::in);
for(i=0;i<SHRT_MAX;++i)
{
datei >> input[i];
}
datei.close();
}
for(i=0;i<SHRT_MAX;i++)
{
waveBuffer[i] = input[i] & 0x00ff;
}
analyse(input);
plotten(input, waveBuffer);
if(ausgabe)
{
uint8_t *wave;
wave = (uint8_t *) malloc(SHRT_MAX+1);
for(i=0;i<SHRT_MAX;i++) wave[i] = waveBuffer[i];
playCaptured(wave, SHRT_MAX, "plughw:1,0", 1, 12000, 8);
free(wave);
}
return 1;
}
moin!
schön, dass du weitergekommen bist!
Leider kann ich unmöglich auf meinem Pi z.Zt programmieren, ich habe hier nur einen 7" Miniscreen zur Verfügung -
ich habe die Funktionen daher auf dem PC ein wenig "offline" umgearbeitet.
Zu den Editor-Einrückungen:
könntest du sie bitte immer auf 3 setzen? sonst passen große Funktions- und Loop-Verschachtelungen nicht mehr in 1 Zeile, da zu weit eingerückt.
zur Plot-Funktion - die musste abgeändert werden.
zuerst, dieser ganze Teil zur Initialisierung von OpenVG gehört in eine Funktion mit fester Fenstergröße, z.B. 1024x600
dabei müssen
int _width_=1024, _height_=600;
globale Variablen werden;
Ich habe sie jetzt mit Unterstrichen im Namen definiert, damit sie besser als globale Variablen erkennbar sind.
initOpenVG() wird in main() oder dem Task aufgerufen, der später für den Screen zuständig ist - in unserem Fall also z.Zt. noch main().Code:int _width_=1024, _height_=600;
initOpenVG() {
initWindowSize(0, 0, _width_, _height_);
init(&_width_, &_height_);
Start(_width_, _height_);
Background(0, 0, 0);
StrokeWidth(1.0);
WindowOpacity(200);
WindowClear();
}
StrokeWidth(1.0);
braucht dann nie mehr neu aufgerufen werden, außer man ändert es
dasselbe gilt für alle anderen Variablen hier in initOpenVG().
finish() gehört als letzter Befehl in die aufrufende Graph-Init-Funktion,
d.h. z.Zt in main() also kurz for exit(0).
Weiter schlage ich vor, in den Funktionen nicht die Bezeichner der globalen Arrays oder anderer Funktionen zu verwenden, das verwirrt -
stattdessen einfach * array, samt Übergabe der Länge.
Denn später ändert sich ja auch noch die Plot-Länge aufs doppelte.
Auch darf die Plot-Funktion immer nur den übergebenen Array plotten, nicht 2 auf einmal.
Deine plot Funktion lautet dann fürs erste:
Hier verstehe ich aber dein 3. + 4. Argument von Line() nicht: wieso i+1 ?Code:// **SNIP**
for(i=0;i<arrlength;i++)
{
Line((VGfloat) schritt*i, (VGfloat) input[i], (VGfloat) schritt*(i+1), (VGfloat) input[i+1]); // <<<< Fehler ????
}
das Koordinatensystem hat die x-Achse an der Basislinie y0 im Fenster,
die Linien werden also gezeichnet von
xi, y0
nach
xi, (y0 + array[i])
(xi ist der i-te Schritt auf der x-Achse;
der Skalierungsfaktor xscale für die Schritte der xi-Werte kann von plotArray an Hand der array-Länge ausgerechnet werden.
Willst du 2 Koordinatensysteme untereinander malen, kannst du noch eine y0-Postion als Basislinie mit übergeben an plotArray
Code:void plotArray((int32_t *array, int32_t arrlength, int y0) {
float xscale=1.0, border=100.0; // border anpassen !
xscale = (float) (arrlength-border)/_width_; // Ausschöpfung der gesamten openVG-Window-Breite width samt Rand!
Fill(0, 255, 255, 1);
for(i=0;i<arrlength;i++)
{
Line((VGfloat)xscale*i, (VGfloat) y0, (VGfloat)xscale*i, (VGfloat)(y0+input[i]) );
}
End();
}
die Steuerung mit getch() dagegen gehört in die aufrufende Funktion, also analyse, da wo man einen array gerade fertig gerechnet hat.
WindowClear();
muss dann ggf. direkt vor den plotArray-Aufruf.
Auch in analyse solle nicht input oder wavebuffer stehen, sondern nur allgemein array.
analyse wird dann wiederum allgemein von main() oder einer anderen Funktion aufgerufen, ebenfalls mit arrlength als allgemeinen Längenparameter, damit man flexibel bleibt für verschieden lange arrays zum Analysieren:
Code:void analyse(int32_t *array, int32_t arrlength) // leicht verändert !!
{
int32_t sbuf[128];
int32_t bias, minr, maxr, baseline,
signalstart, signalend;
int32_t maximum = array[0];
int32_t minimum = array[0];
int32_t maxpos, minpos;
int32_t i;
char s[3];
for(i=0;i<arrlength;i++)
{
if(array[i] > maximum)
{
maximum = array[i];
maxpos = i;
}
if(array[i] < minimum)
{
minimum = array[i];
minpos = i;
}
}
maximum = array[0];
minimum = array[0];
for(i=0;i<arrlength; ++i)
{
if(array[i] > maximum)
{
maximum = array[i];
maxpos = i;
}
if(array[i] < minimum)
{
minimum = array[i];
minpos = i;
}
}
// calculate baseline from last 100 array cells:
// init vars
baseline=(array[minpos] + array[maxpos]) / 2; // init baseline by (min+max)/2
minr=baseline - 1;
maxr=baseline + 1;
// auto-adjust:
for(i=arrlength-100; i<arrlength; ++i)
{
// mean baseline
baseline = round((0.5*(float)array[i] + 0.5*(float)baseline)) ;
// smoothed out max noise
if(array[i] >= baseline) maxr = round((0.6*(float)array[i] + 0.4*(float)maxr)) +1 ;
// smoothed out min noise
if(array[i] <= baseline) minr = round((0.6*(float)array[i] + 0.4*(float)minr)) -1 ;
}
bias = max(baseline-minr, maxr-baseline) +1;
// noise reduction start/end
// drop small noise
for(i=0;i<arrlength;++i)
{
if((array[i]>baseline) && (array[i] <= baseline + bias)) array[i] = baseline ; // little higher value => drop to baseline
else
if((array[i]<baseline) && (array[i] >= baseline - bias)) array[i] = baseline ; // little lower value => rise to baseline
}
// signalstart, signalend: threshold = bias + (bias/2)
signalstart = 0;
i = 0;
while((array[i]<=baseline + 4 * bias/3) && (i<arrlength-1)) ++i;
signalstart = i;
if(i > 0) signalstart -= 1;
signalend=arrlength-1;
i=arrlength-1;
while((array[i]<=baseline + + 4*bias/3) && (i>signalstart)) --i;
signalend = i;
if(i<arrlength-1) signalstart +=1;
sStart = signalstart;
sEnde = signalend;
WindowClear();
plotArray(array, arrlength, 30); // 30 = baseline ordinate // <<<<<<<<<<< neu
// >>>> Tabelle stattdessen ins Graphic window ?
cout << "Bias: " << bias << endl;
cout << "Maximal: " << maximum << endl;
cout << "Minimal: " << minimum << endl;
cout << "Signalstart: " << signalstart << endl;
cout << "Signalende: " << signalend << endl;
}
ich habe auch noch openVG-Hilfsfunktionen für Farbe und zur Textausgabe im Grafikfenster eingearbeitet (z.B. zur Beschriftung der Charts oder weiterer Tabellenwete), das kann dann anstelle der obigen initOpenVG komplett folgendermaßen in das Spracherkennungsprogramm übernommen werden:
Code:#include "VG/openvg.h"
#include "VG/vgu.h"
#include "fontinfo.h"
#include "shapes.h"
//*************************************************************
// openVG
//*************************************************************
// color name constants
#define BLACK 0, 0, 0
#define WHITE 255, 255, 255
#define MAGENTA 255, 0, 255
#define RED 255, 0, 0
#define YELLOW 255, 255, 0
#define LIME 0, 255, 0
#define GREEN 0, 128, 0
#define CYAN 0, 255, 255
#define AQUA 102, 204, 204
#define BLUE 0, 0, 255
int _width_=1024, _height_=600;
int _fontsize_ = 10;
#define cls() WindowClear()
//*************************************************************
inline void lcdprintxy( VGfloat x, VGfloat y, char * buf ) {
Text( (x+_fontsize_), (y+_fontsize_*1.2), buf, MonoTypeface , _fontsize_);
}
//*************************************************************
void initOpenVG() {
initWindowSize(0, 0 , _width_ , _height_ );
init(&_width_, &_height_);
Start(_width_, _height_);
Background(BLACK);
Stroke(WHITE, 1);
StrokeWidth(1.0);
Fill(WHITE, 1);
WindowOpacity(200);
cls();
}
//*************************************************************
void plotArray((int32_t *array, int32_t arrlength, int y0) {
float xscale=1.0, border=100.0; // border anpassen !
xscale = (float) (arrlength-border)/_width_; // Ausschöpfung der gesamten openVG-Window-Breite width samt Rand!
Fill(0, 255, 255, 1);
for(i=0;i<arrlength;i++)
{
Line((VGfloat)xscale*i, (VGfloat) y0, (VGfloat)xscale*i, (VGfloat)(y0+input[i]) );
}
End();
}
//*************************************************************
Hast du irgendwelche weiterführende Pläne mit dem Programm? Du strickst das so munter um das ich langsam das Gefühl kriege das Programm hat längerfristig eine Bedeutung. Ich dachte bisher aber eigentlich es handelt sich um eine Art Versuchsanordnung um die Grundlagen zu erarbeiten.
Was ich jetzt nicht verstehe, ich rufe die Funktion zum Plotten genau einmal auf. Das heisst sie wird nur einmal abgearbeitet. Was macht es da für einen Sinn das Ganze in Main zu arbeiten?
Warum ich i+1 mache? Ich mache eine Linie von Punkt 1, also aktuelle x und y hin zum nächsten Punkt. Also x (bzw. i) +1 für den nächsten Eintrag im Array. Funktioniert ja auch.
Wo liegt das Problem zwei Arrays zu Plotten? Dadurch verändert sich nichts.
Wenn du nicht direkt am Raspi arbeiten kannst? Warum machst du es dann nicht über ssh?
ich kann kein ssh und werde es auch nie nutzen. Ist so ein Linux Ding, das ich einfach nicht mag. ;)
wir werden plotArray noch öfter brauchen, aber immer nur einfach, eins nach dem anderen, das oben war ja nur der Anfang.
1. Aufruf: array unverändert
2. Aufruf: Rauschen raus und Wort Grenzen ermittelt.
3. Aufruf: Wort herausschneiden und ganz an den Anfang eines neuen Arrays setzen
Probier mal bitte meine Funktion plotArray zu verwenden, deine ist mir völlig unklar, auch wegen der x-Achsen-Skalierung und der gezielten Ausgabe an bestimmten Stellen im Fenster, alleine oder zu mehreren.
Dann geht es weiter wie hier skizziert:
https://www.roboternetz.de/community...l=1#post628055
wir können dann bald die veränderten wav files mit den unveränderten per FFT vergleichen.
- - - Aktualisiert - - -
ps,
eigentlich würde es sogar reichen, nur Punkte zu setzen, keine Linien zu malen:
statt
void Line(VGfloat x1, VGfloat y1, VGfloat x2, VGfloat y2)
jetzt
void Point(VGfloat x, VGfloat y)
ich finde aber keine entsprechende API Funktion.
So ich bin schon am umbauen. Funktioniert soweit. Nur habe ich irgendwie so das Gefühl das man bei deiner Variante nicht so gut sieht wie bei meiner.
Generell, warum ist die dieser von unten nach Oben zeichen Variante lieber wie die die ich genommen hate? Nach meiner Variante wird es doch auch in anderen Soundprogrammen angezeigt.
Was ssh angeht. Ja es mag eine Linux Geschichte sein, nur verstehe ich dein Problem damit nicht ganz. Ich nehme mal stark an du startest das compilierte Programm jetzt auch in einem Terminal auf dem Raspi. Dann ist der Unterschied eigentlich super gering. Mittels Putty kannst du eine Verbindung zum Raspi aufbauen- Dabei hast du dann ja einen Terminal der eben nur auf deinem Windows läuft anstatt auf dem Raspi. Nicht einmal auf deinem Windows läuft sondern nur auf diesem angezeigt wird. Wenn du dort dannCode:#include <iostream>
#include <vector>
#include <fstream>
#include <string>
#include <stdio.h>
#include <limits.h>
#include <math.h>
#include <VG/openvg.h>
#include <VG/vgu.h>
#include <fontinfo.h>
#include <shapes.h>
#include "diaSound.hpp"
bool ausgabe = true;
int _width_=1024, _height_=600;
void initOpenVG()
{
initWindowSize(0, 0, _width_, _height_);
init(&_width_, &_height_);
Start(_width_, _height_);
Background(0, 0, 0);
StrokeWidth(1.0);
WindowClear();
}
void plotArray(int32_t *array, int32_t arrlength, int y0)
{
float xscale=1.0, border=100.0;
xscale = (float) (arrlength-border)/_width_;
int i;
Fill(0, 255, 255, 1);
Stroke(0, 255, 255, 1);
for(i=0;i<arrlength;i++)
{
Line((VGfloat)xscale*i, (VGfloat) y0, (VGfloat)xscale*i, (VGfloat)(y0+array[i]));
}
End();
}
void analyse(int32_t *array, int32_t arrlength)
{
int32_t sbuf[128];
int32_t bias, minr, maxr, baseline,
signalstart, signalend;
int32_t maximum = array[0];
int32_t minimum = array[0];
int32_t maxpos, minpos;
int32_t i;
for(i=0;i<arrlength;i++)
{
if(array[i] > maximum)
{
maximum = array[i];
maxpos = i;
}
if(array[i] < minimum)
{
minimum = array[i];
minpos = i;
}
}
maximum = array[0];
minimum = array[0];
for(i=0;i<arrlength; ++i)
{
if(array[i] > maximum)
{
maximum = array[i];
maxpos = i;
}
if(array[i] < minimum)
{
minimum = array[i];
minpos = i;
}
}
// calculate baseline from last 100 array cells:
// init vars
baseline=(array[minpos] + array[maxpos]) / 2; // init baseline by (min+max)/2
minr=baseline - 1;
maxr=baseline + 1;
// auto-adjust:
for(i=arrlength-100; i<arrlength; ++i)
{
// mean baseline
baseline = round((0.5*(float)array[i] + 0.5*(float)baseline)) ;
// smoothed out max noise
if(array[i] >= baseline) maxr = round((0.6*(float)array[i] + 0.4*(float)maxr)) +1 ;
// smoothed out min noise
if(array[i] <= baseline) minr = round((0.6*(float)array[i] + 0.4*(float)minr)) -1 ;
}
bias = max(baseline-minr, maxr-baseline) +1;
// noise reduction start/end
// drop small noise
for(i=0;i<arrlength;++i)
{
if((array[i]>baseline) && (array[i] <= baseline + bias)) array[i] = baseline ; // little higher value => drop to baseline
else
if((array[i]<baseline) && (array[i] >= baseline - bias)) array[i] = baseline ; // little lower value => rise to baseline
}
// signalstart, signalend: threshold = bias + (bias/2)
signalstart = 0;
i = 0;
while((array[i]<=baseline + 4 * bias/3) && (i<SHRT_MAX-1)) ++i;
signalstart = i;
if(i > 0) signalstart -= 1;
signalend=arrlength-1;
i=arrlength-1;
while((array[i]<=baseline + + 4*bias/3) && (i>signalstart)) --i;
signalend = i;
if(i<arrlength-1) signalstart +=1;
if(ausgabe)
{
cout << "Bias: " << bias << endl;
cout << "Maximal: " << maximum << endl;
cout << "Minimal: " << minimum << endl;
cout << "Signalstart: " << signalstart << endl;
cout << "Signalende: " << signalend << endl;
}
}
int main(int argc, char *argv[])
{
fstream datei;
int32_t waveBuffer[SHRT_MAX];
int32_t i;
char s[3];
initOpenVG();
if(argc <= 1) audioCapture(waveBuffer, SHRT_MAX, "plughw:1,0", 1, 12000, 8);
else
{
datei.open(argv[1], ios::in);
for(i=0;i<SHRT_MAX;++i)
{
datei >> waveBuffer[i];
}
datei.close();
}
for(i=0;i<SHRT_MAX;i++)
{
waveBuffer[i] = waveBuffer[i] & 0x00ff;
}
plotArray(waveBuffer, SHRT_MAX, 0);
analyse(waveBuffer, SHRT_MAX);
plotArray(waveBuffer, SHRT_MAX, 255);
if(ausgabe)
{
uint8_t *wave;
wave = (uint8_t *) malloc(SHRT_MAX+1);
for(i=0;i<SHRT_MAX;i++) wave[i] = waveBuffer[i];
playCaptured(wave, SHRT_MAX, "plughw:1,0", 1, 12000, 8);
free(wave);
}
fgets(s, 2, stdin);
finish();
return 1;
}
startet geany auf dem Raspi und leitet seine GUI auf dein Windows um. Es läuft also prinzipiell Alles genau so wie auf dem Raspi.Wäre ja zumindest für den Übergang sinnvoll.Code:geany &
ja, ich glaube ich habe inzwischen auch verstanden, was du machst, du verbindest die Oberkanten der Ausschläge, das gibt eine Art "Obere Umrandungslinie".
Ich habe die Spikes verwendet, weil sie den Hintergrund komplett einfärben und damit kontrastreicher sind (siehe Arduino Plots).
Zum Starten:
nein, ich starte das programm entweder über Geany F5 oder ich starte es im Filemanager (was bei wiringPi nicht geht, wegen sudo-Pflicht) -
oder ich lege einen Link auf den Desktop (Ausführen per sudo).
Solange ich aber damit viel noch rumprogrammiere: immer nur per Geany F5.
Ein Terminal verwende ich nie, diese Un-Toten lasse ich ruhen, und Putty ist für mich Teufelswerk ;)
Ab Mittwoch spätestens habe ich meinen großen Raspi Screen wieder und kann wieder lokal kompilieren :)
Du willst also lieber die oberen Ausschläge haben?
Für einen C Programmierer bist du aber ziemlich unflexibel ;-).
Ich sage es dir auch nur ungerne aber die Meisten die aktiv programmieren, sei es bei Google oder Microsoft oder wo auch immer, benutzen diese Un-Toten ^^.
moin!
ich schätze die C-Syntax sehr, weil sie ungeheuer mächtig und perfekt prozedural strukturierbar ist, aber ich bin Hobby-Programmierer und IDEs und USB-p'n'p gewöhnt (wie bei der Arduino IDE oder der Lego BricxCC IDE), und ich würde mich niemals als "typischen" C-Programmierer bezeichnen (C++ beherrsche ich selber gar nicht). Mit der ganzen Linkerei und make, makefile, .so files, logins und IPs will ich nichts zu tun haben, auch nichts mit Terminals (außer automatisch per USB verbinden ohne weitere Einstellungen wie bei Arduino und Serial).
IDE komplett installieren per setup.exe etc.
Programm schreiben in einer IDE
Compilieren per Tastendruck
Hochladen per Tastendruck (falls nötig)
Starten per Doppelklick oder Tastendruck
- so einfach muss Hobbyprogrammieren gehen, das ist mein Level, und genau so funktioniert ja auch Arduino.
was die Anzeige angeht: so wie bei meinem Code-Voschlag oben wäre es eigentlich perfekt, da auch auf kleinen Screens (5", 7") dann skalierbar und gut erkennbar.
Code:
void plotArray((int32_t *array, int32_t arrlength, int y0) {
float xscale=1.0, border=100.0; // border anpassen !
xscale = (float) (arrlength-border)/_width_; // Ausschöpfung der gesamten openVG-Window-Breite width samt Rand!
Fill( CYAN, 1 );
for(i=0;i<arrlength;i++)
{
Line((VGfloat)xscale*i, (VGfloat) y0, (VGfloat)xscale*i, (VGfloat)(y0+input[i]) );
}
End();
}
Du teilst falsch. Du musst die Bildbreite durch die array Länge teilen, nicht umgekehrt.
sind noch weitere Änderungen im Code drin.Code:#include <iostream>
#include <vector>
#include <fstream>
#include <string>
#include <stdio.h>
#include <limits.h>
#include <math.h>
#include <VG/openvg.h>
#include <VG/vgu.h>
#include <fontinfo.h>
#include <shapes.h>
#include "diaSound.hpp"
#define BLACK 0, 0, 0
#define WHITE 255, 255, 255
#define MAGENTA 255, 0, 255
#define RED 255, 0, 0
#define YELLOW 255, 255, 0
#define LIME 0, 255, 0
#define GREEN 0, 128, 0
#define CYAN 0, 255, 255
#define AQUA 102, 204, 204
#define BLUE 0, 0, 255
int _width_=1024, _height_=600;
int _fontsize_ = 10;
bool ausgabe = true;
void initOpenVG()
{
initWindowSize(0, 0, _width_, _height_);
init(&_width_, &_height_);
Start(_width_, _height_);
Background(0, 0, 0);
StrokeWidth(1.0);
WindowClear();
}
void plotArray(int32_t *array, int32_t arrlength, int y0)
{
float xscale=1.0, border=100.0;
xscale = _width_ / (float) (arrlength-border);
int i;
Fill(CYAN, 1);
Stroke(0, 255, 255, 1);
for(i=0;i<arrlength;i++)
{
Line((VGfloat)xscale*i, (VGfloat) y0, (VGfloat)xscale*i, (VGfloat)(y0+array[i]));
}
End();
}
void analyse(int32_t *array, int32_t arrlength)
{
int32_t sbuf[128];
int32_t bias, minr, maxr, baseline,
signalstart, signalend;
int32_t maximum = array[0];
int32_t minimum = array[0];
int32_t maxpos, minpos;
int32_t i;
for(i=0;i<arrlength;i++)
{
if(array[i] > maximum)
{
maximum = array[i];
maxpos = i;
}
if(array[i] < minimum)
{
minimum = array[i];
minpos = i;
}
}
maximum = array[0];
minimum = array[0];
for(i=0;i<arrlength; ++i)
{
if(array[i] > maximum)
{
maximum = array[i];
maxpos = i;
}
if(array[i] < minimum)
{
minimum = array[i];
minpos = i;
}
}
// calculate baseline from last 100 array cells:
// init vars
baseline=(array[minpos] + array[maxpos]) / 2; // init baseline by (min+max)/2
minr=baseline - 1;
maxr=baseline + 1;
// auto-adjust:
for(i=arrlength-100; i<arrlength; ++i)
{
// mean baseline
baseline = round((0.5*(float)array[i] + 0.5*(float)baseline)) ;
// smoothed out max noise
if(array[i] >= baseline) maxr = round((0.6*(float)array[i] + 0.4*(float)maxr)) +1 ;
// smoothed out min noise
if(array[i] <= baseline) minr = round((0.6*(float)array[i] + 0.4*(float)minr)) -1 ;
}
bias = max(baseline-minr, maxr-baseline) +1;
// noise reduction start/end
// drop small noise
for(i=0;i<arrlength;++i)
{
if((array[i]>baseline) && (array[i] <= baseline + bias)) array[i] = baseline ; // little higher value => drop to baseline
else
if((array[i]<baseline) && (array[i] >= baseline - bias)) array[i] = baseline ; // little lower value => rise to baseline
}
// signalstart, signalend: threshold = bias + (bias/2)
signalstart = 0;
i = 0;
while((array[i]<=baseline + 4 * bias/3) && (i<SHRT_MAX-1)) ++i;
signalstart = i;
if(i > 0) signalstart -= 1;
signalend=arrlength-1;
i=arrlength-1;
while((array[i]<=baseline + + 4*bias/3) && (i>signalstart)) --i;
signalend = i;
if(i<arrlength-1) signalstart +=1;
if(ausgabe)
{
cout << "Bias: " << bias << endl;
cout << "Maximal: " << maximum << endl;
cout << "Minimal: " << minimum << endl;
cout << "Signalstart: " << signalstart << endl;
cout << "Signalende: " << signalend << endl;
}
}
int main(int argc, char *argv[])
{
fstream datei;
int32_t waveBuffer[SHRT_MAX];
int32_t i;
char s[3];
initOpenVG();
if(argc <= 1) audioCapture(waveBuffer, SHRT_MAX, "plughw:1,0", 1, 12000, 8);
else
{
datei.open(argv[1], ios::in);
for(i=0;i<SHRT_MAX;++i)
{
datei >> waveBuffer[i];
}
datei.close();
}
for(i=0;i<SHRT_MAX;i++)
{
waveBuffer[i] = waveBuffer[i] & 0x00ff;
}
plotArray(waveBuffer, SHRT_MAX, 0);
analyse(waveBuffer, SHRT_MAX);
plotArray(waveBuffer, SHRT_MAX, 255);
if(ausgabe)
{
uint8_t *wave;
wave = (uint8_t *) malloc(SHRT_MAX+1);
for(i=0;i<SHRT_MAX;i++) wave[i] = waveBuffer[i];
playCaptured(wave, SHRT_MAX, "plughw:1,0", 1, 12000, 8);
free(wave);
}
fgets(s, 2, stdin);
SaveEnd("plott.raw");
finish();
return 1;
}
klar, stimmt ntl mit dem Teilen! :rolleyes:
(das ist der Nachteil vom offline Programmieren ;) )
mit dem if (ausgabe) und dem if(argc) komme ich allerdings nicht klar, denn ich starte ja aus geany heraus und nie von der Kommandozeile aus.
Vielleicht könnten wir später ein Menü einbauen, im Moment ist es aber eh nicht wichtig, denn die nächsten Schritte wären ja laut
https://www.roboternetz.de/community...l=1#post628055
da wir das Plotten ja inzwischen mit variabler Basislinie machen können, könnte man alle 2-3 Plots für den Anfang immer untereinander im selben Fenster anzeigen:Zitat:
a) du nimmst eine Reihe von Wort-Samples auf:
JA_raw.wav
NEIN_raw.wav
STOPP_raw.wav
b) der Micro- bzw. file- input[] array wird als Plot angezeigt
und dann direkt nach analyse geschickt und noise und Wort-Grenzen ermittelt.
c) jetzt wird NUR das Wort innerhalb der Wort-Grenzen nach wavbuffer kopiert
Code:
memset(wavebuffer, 0, sizeof(wavebuffer) );
memcpy(wavebuffer, input+(signalstart*sizeof(char)), (signalend-signalstart)*sizeof(int32_t) );
d) Der wave-Puffer startet jetzt an Stelle 0 mit dem wav-Wortsignal, der Rest bleibt 0.
Der neue wav-Puffer wird ebenfalls als Plot angezeigt.
e) dann wird das "neue" wavebuffer-Muster als .wav Datei gespeichert.
JA_opt.wav
NEIN_opt.wav
STOPP_opt.wav
a) unverändert: y0=300-400
b) ent-rauscht: y0=200 (kann entfallen)
c) geschnitten: y0=1
Das dient zur in-Prozess-Kontrolle bei den vorhergehenden und den folgenden Schritten...
denn dann käme ja als nächstes eine kleine Erweiterung der alsa-API mit den vereinfachten Funktionen zum schnelleren abspielen, aufnehmen und um-kopieren von files und arrays nacheinander und ineinander:
a) record_wave(int32_t * array, int32_t length); // Aufnahme von Tönen über Soundkarte => input-array
ähnlich wie audioCapture(input, SHRT_MAX, "plughw:1,0", 1, 12000, 8 );
b) save_wave2file(int32_t * array, char * filename); // speichern eines arrays als .wav File mit header
=> fehlt noch ?
c) wavefile2Array(int32_t * array, char * filename); // lesen von einem .wav File => in input-array
(extrahiert ohne header, nur data, ohne audio-Wiedergabe über Soundkarte)
d) play_waveArray(int32_t * array, int32_t length); // abspielen eines arrays mit festen Parametern
ähnlich wie playCaptured(wave, SHRT_MAX, "plughw:1,0", 1, 12000, 8 );
e) play_waveFile(char * filename); // abspielen eines wav-files mit Parametern laut Header-Daten,
ohne kopieren in einen temporären Array, ähnlich wie playwave(string waveDatei, string name)
Soundkarten-Daten getrennt konfigurieren
In die Sound-Lib sollte man dann noch zusätzlich aufnehmen diese 2 globalen #defines für Soundkarten:
#define SoundCard_Intern "plughw:0,0"
#define SoundCard_Extern "plughw:1,0"
Du bist echt stur mit deinem Geany ;-). Lieber ein Menü rein stricken wie ein Terminal öffnen ^^
Ich bau dir was.
Warum willst du das Ganze als Wave mit Header speichern??
:D
wenn man als Menüpunkt/Aktion wählt "aufnehmen", dann nimmt man einen Sound ja über die Soundkarte als reinen Array auf.
Wenn man ihn jetzt als Muster später wieder benutzen will, muss man ihn ja als .wav speichern.
JA.wav
NEIN.wav
STOPP.wav
Nur dann kann man ja später auch aktuelle Wörter mit allen bekannten gespeicherten Mustern vergleichen, um festzustellen, wie denn das Wort nun heißen mag...
und wenn nichts annähernd identisches vorhanden ist an Mustern, z.B. beidann kann man es gleich als neues .wav Muster speichern, für künftige Vergleiche.Zitat:
VORWÄRTS!
VORWAERTS.wav
und somit hat man dann ein weiteres, neues Wort in seinem Wortschatz.
Und man kann jetzt auch direkt einzelne Wörter seines Wortschatzes abhören, wie sie klingen, und ob sie ggf. noch etwas von der Qualität her verbessert werden können/müssen.
nach jeder Aktion im Programm könnte man also zum Menü zurückkehren:
Kommando-Center:
==============
0 Soundfile *.csv in Programm öffnen / laden (FileOpenDialog)
1 Soundfile *.wav in Programm öffnen / laden (FileOpenDialog)
2 Soundfile *.wav öffnen / abspielen + Plot (FileOpenDialog)
3 Sound aufnehmen per Micro / SoundCard
4 akt. Sound (Array im RAM) abspielen + Plot
5 akt. Sound optimieren (noise/cut)
6 akt. Sound (im RAM) als File speichern unter... (FileSaveDialog)
7 akt. Sound an FFT + Plot
8 akt. Sound cross correlation mit 1 wav File (FileOpenDialog)
9 akt. Sound cross correlation mit allen *.wav Files (auto)
...
Hier erstmal das Menü.
- - - Aktualisiert - - -Code:#include <iostream>
#include <vector>
#include <fstream>
#include <string>
#include <stdio.h>
#include <limits.h>
#include <math.h>
#include <VG/openvg.h>
#include <VG/vgu.h>
#include <fontinfo.h>
#include <shapes.h>
#include "diaSound.hpp"
#define BLACK 0, 0, 0
#define WHITE 255, 255, 255
#define MAGENTA 255, 0, 255
#define RED 255, 0, 0
#define YELLOW 255, 255, 0
#define LIME 0, 255, 0
#define GREEN 0, 128, 0
#define CYAN 0, 255, 255
#define AQUA 102, 204, 204
#define BLUE 0, 0, 255
int _width_=1024, _height_=600;
int _fontsize_ = 10;
string version = "2.0";
bool ausgabe = true;
void initOpenVG()
{
initWindowSize(0, 0, _width_, _height_);
init(&_width_, &_height_);
Start(_width_, _height_);
Background(0, 0, 0);
StrokeWidth(1.0);
WindowClear();
}
void plotArray(int32_t *array, int32_t arrlength, int y0)
{
float xscale=1.0, border=100.0;
xscale = _width_ / (float) (arrlength-border);
int i;
Fill(CYAN, 1);
Stroke(0, 255, 255, 1);
for(i=0;i<arrlength;i++)
{
Line((VGfloat)xscale*i, (VGfloat) y0, (VGfloat)xscale*i, (VGfloat)(y0+array[i]));
}
End();
}
void analyse(int32_t *array, int32_t arrlength)
{
int32_t sbuf[128];
int32_t bias, minr, maxr, baseline,
signalstart, signalend;
int32_t maximum = array[0];
int32_t minimum = array[0];
int32_t maxpos, minpos;
int32_t i;
for(i=0;i<arrlength;i++)
{
if(array[i] > maximum)
{
maximum = array[i];
maxpos = i;
}
if(array[i] < minimum)
{
minimum = array[i];
minpos = i;
}
}
maximum = array[0];
minimum = array[0];
for(i=0;i<arrlength; ++i)
{
if(array[i] > maximum)
{
maximum = array[i];
maxpos = i;
}
if(array[i] < minimum)
{
minimum = array[i];
minpos = i;
}
}
// calculate baseline from last 100 array cells:
// init vars
baseline=(array[minpos] + array[maxpos]) / 2; // init baseline by (min+max)/2
minr=baseline - 1;
maxr=baseline + 1;
// auto-adjust:
for(i=arrlength-100; i<arrlength; ++i)
{
// mean baseline
baseline = round((0.5*(float)array[i] + 0.5*(float)baseline)) ;
// smoothed out max noise
if(array[i] >= baseline) maxr = round((0.6*(float)array[i] + 0.4*(float)maxr)) +1 ;
// smoothed out min noise
if(array[i] <= baseline) minr = round((0.6*(float)array[i] + 0.4*(float)minr)) -1 ;
}
bias = max(baseline-minr, maxr-baseline) +1;
// noise reduction start/end
// drop small noise
for(i=0;i<arrlength;++i)
{
if((array[i]>baseline) && (array[i] <= baseline + bias)) array[i] = baseline ; // little higher value => drop to baseline
else
if((array[i]<baseline) && (array[i] >= baseline - bias)) array[i] = baseline ; // little lower value => rise to baseline
}
// signalstart, signalend: threshold = bias + (bias/2)
signalstart = 0;
i = 0;
while((array[i]<=baseline + 4 * bias/3) && (i<SHRT_MAX-1)) ++i;
signalstart = i;
if(i > 0) signalstart -= 1;
signalend=arrlength-1;
i=arrlength-1;
while((array[i]<=baseline + + 4*bias/3) && (i>signalstart)) --i;
signalend = i;
if(i<arrlength-1) signalstart +=1;
if(ausgabe)
{
cout << "Bias: " << bias << endl;
cout << "Maximal: " << maximum << endl;
cout << "Minimal: " << minimum << endl;
cout << "Signalstart: " << signalstart << endl;
cout << "Signalende: " << signalend << endl;
}
}
int main(int argc, char *argv[])
{
fstream datei;
int32_t waveBuffer[SHRT_MAX];
int32_t i;
char s[3], m[3];
initOpenVG();
system("clear");
cout << endl << "HaWe und Hirnfreis's Sound Experiment V " << version << endl << endl;
cout << " 1. Audio aufnahme" << endl;
cout << " 2. input.csv abspielen" << endl;
cout << " 3. waveBuffer.csv abspielen" << endl << endl;
cout << " Bitte wählen: ";
fgets(m, 2, stdin);
if(strcmp(m, "1") == 0)
{
cout << endl << "Starte Aufnahmne... " << endl << endl;
audioCapture(waveBuffer, SHRT_MAX, "plughw:1,0", 1, 12000, 8);
cout << endl << "Aufnahmne beendet! " << endl << endl;
}
if(strcmp(m, "2") == 0)
{
cout << endl << "Spiele input.csv ab!" << endl << endl;
datei.open("input.csv", ios::in);
for(i=0;i<SHRT_MAX;++i)
{
datei >> waveBuffer[i];
}
datei.close();
}
if(strcmp(m, "3") == 0)
{
cout << endl << "Spiele waveBuffer.csv ab!" << endl << endl;
datei.open("waveBuffer.csv", ios::in);
for(i=0;i<SHRT_MAX;++i)
{
datei >> waveBuffer[i];
}
datei.close();
}
for(i=0;i<SHRT_MAX;i++)
{
waveBuffer[i] = waveBuffer[i] & 0x00ff;
}
plotArray(waveBuffer, SHRT_MAX, 0);
analyse(waveBuffer, SHRT_MAX);
plotArray(waveBuffer, SHRT_MAX, 255);
if(ausgabe)
{
uint8_t *wave;
wave = (uint8_t *) malloc(SHRT_MAX+1);
for(i=0;i<SHRT_MAX;i++) wave[i] = waveBuffer[i];
playCaptured(wave, SHRT_MAX, "plughw:1,0", 1, 12000, 8);
free(wave);
}
fgets(s, 2, stdin);
SaveEnd("plott.raw");
finish();
return 1;
}
Ich sehe aber keinen Grund da ein wave draus zu bauen. speichern und abspielen kann man auch mit meiner Variante und muss nicht erst noch Header erstellen und auslesen# Wäre in meinen Augen nur unnötiger Aufwand.
das ging ja super schnell! :)
allerdings soll nicht csv geladen / abgespielt / gespeichert werden, sondern *.wav Dateien (ggf. ~auswahl wie im Filebrowser).
Gespeichert werden sollen nur echte .wav Formate, keine reinen Arrays.
das Konzept ist:
im RAM befindet sich immer ein Array mit den reinen sound data,
auf der SD befinden sich viele (!) .wav Dateien: die bilden den Wortschatz bekannter (zu erkennender) Wortbefehle.
Sie müssen während der Testphase und auch später im Automatik-Betrieb nacheinander geöffnet, gespielt, bearbeitet und verglichen werden können.
Zum Bearbeiten werden .wav Files geöffnet und die reinen sound data in einen array ins RAM kopiert,
Per Micro wird auch nur ein Array im RAM belegt,
bei Speichern wird aber wieder der komplette wav-Header davor geschrieben.
dazu dienen unsere Werkzeuge, und die sind:
a) record_wave(int32_t * array, int32_t length);
b) save_wave2file(int32_t * array, char * filename);
c) wavefile2Array(int32_t * array, char * filename);
d) play_waveArray(int32_t * array, int32_t length);
e) play_waveFile(char * filename);
sowie
f) plotArray(int32_t * array, int32_t length, int y0);
g) analyseArray(int32_t * array, int32_t length);
h) array2FFT(int32_t * array, int32_t length, double * fx, double * fy, int32_t FFT_length);
i) cross_corr(int32_t * array, int32_t * pattern, int32_t length);
...usw...
Wie im Filebrowser??????????????????????????? Der Aufwand wird etwas gross! Je nachdem wie viele Dateien das sind muss dann auch noch aufteilen und scrollen usw. rein. Also das ist mir dann doch zu viel des Guten.
Aber nochmal. Was spricht gegen das Speichern des Array? Ich sehe keinen Sinn darin ein ganzes Wave da zu bauen.
wir sollten jederzeit immer einfach einen File im Browser abspielen können, um ihn jederzeit hören zu können.
Und stell dir vor, wir haben einen Wortschatz von ein paar Dutzend Wörtern, und die Worterkennung klappt am Anfang nicht (wie sicher zu erwarten ist), dann muss man die Files einfach auswählen können, einzeln laden, und einfach mit anderen cross-correlieren.
Wenn der Dateizugriff da nicht einfach per Auswahlmenü möglich ist (einfache Liste mit scroll-bar, wie früher im Norton Commander), dann tippt man sich ja nen Wolf und sitzt nächstes Jahr mit der paarweisen cross-correlation noch dran ;)
wenn du allerdings nur 2 oder 3 Wort-Befehle programmieren willst, und dabei bleibts dann auch, dann ist die Sache einfacher zu händeln...... aber sonst, mit mehr, wächst der Verwaltungsaufwand eben exponentiell....
Hast du so ein Menü schon einmal selbst gebaut? In Secondlife habe ich solche Menüs mit Auswahlmenü gegen Geld programmiert,weil es sonst keiner machen wollte. Das ist schon ein fetter Aufwand. Wenn du das übernehmen möchtest freue ich mich auf das Ergebnis ;).
Ich verstehe dich aber richtig. Eine Eingabe über das Mikro wird mit verschiedenen Dateien verglichen. Bzw. Eine ausgewählte Aufnahmen wird mit den Anderen verglichen. Soweit bin ich da noch richtig oder?
ich hatte damals bei NXC etwa 10 Wörter zu verwalten, und da war der Aufwand überschaubar, und es ging ja ohne FFT.
Hast du dir das Programm einmal angeschaut?
Auch einen Filebrowser ähnlich dem Norton Commander habe ich schon einmal selber programmiert, mit Maus- und Tastatursteuerung, auf der Basis von Pascal-File-Funktionen
FindFirst(pattern),
FindNext()
unabhängig davon, in Turbo Pascal.
Unterschätze den Aufwand nicht, der für Spracherkennung betrieben werden muss, dass ist kein Spaziergang im Park.
Ohne bedienerfreundliche (programmiererfreundliche) Entwickler-, Hilfs- und insb. Dateizugriffswekzeuge, die wir alle selber erstellen müssen, sehe ich da kein Land am Horizont.
ja, das stimmt,Zitat:
Eine Eingabe über das Mikro wird mit verschiedenen Dateien verglichen. Bzw. Eine ausgewählte Aufnahmen wird mit den Anderen verglichen. Soweit bin ich da noch richtig oder?
dann wird der jeweilige Fehler ermittelt,
und das mit dem kleinsten Fehler ist das am besten passendste Wort.
Wenn der Fehler überall zu groß ist (bestimmter Schwellwert), oder das vorgeschlagene Wort falsch ist, dann kann das aktuelle Wort als neues Wort gespeichert werden.
Bevor unser Programm irgendwann so weit ist, dass es die ganzen Analysen automatisch selber machen kann, müssen wir sie erstmal mühsam alle einzeln manuell durchführen, dann testen, optimieren, und erneut durchführen können.
Ich schau mir das mal an. Werde aber so oder so bis Mittwoch, im ungünstigen Fall sogar erst Donnerstag nicht wirklich was am Programm arbeiten können. Wundere dich also nicht wenn es im Moment nicht wirklich voran geht.
kein Problem, das mit der Spracherkennung ist ja eh dein Projekt, ich will hier ja nur mit der FFT samt cross-correlation helfen (und weil mich das mit der FFT im Vergleich zu meiner alten NXC-Methode ntl auch selber interessiert) ... 8)
In jedem Fall wären diese File- und Steuer-Menüs aber sowieso erst der 3. Schritt, nach dem alles erstmal mit
Ja.wav, NEIN.wav, STOPP.wav
grob vorgetestet wurde.
Eventuell klappen die File- und Steuer-Menüs aber auch schon z.B. mit Zenity und popen ich bin da dran.
jawohl, File Open-Menüs klappen wunderbar!
Können einfach ins Programm mit eingebunden werden, siehe hier:
(Dank an peterfido + sisor !)
https://www.roboternetz.de/community...l=1#post628328
So. Hat länger gedauert wie ich dachte :-(.
Bin jetzt aber wieder am Start, spätestens morgen gehts weiter!
Die Idee mit Zenity hatte ich auch schon ^^
alles klar!
zum hiesigen Thema *.wav files spielen/lesen/speichern fehlt ja dann nur noch, wie man einen Array als kompletten *.wav lädt und speichert (beides mit Zenity),
im Gegensatz zu Menüpunkt
als *.csv speichern
müsste dann dafür ja nur zusätzlich noch der wav Header davor.
Und dann kommt so langsam der Teil mit der FFT - hier ist ein Link zur Einführung, samt FFT Code:
http://paulbourke.net/miscellaneous/dft/
(für unsere Anwendung: int64_t statt long! )
- - - Aktualisiert - - -
noch eine Bitte:
könntest du bitte nochmal die aktuelle Version deiner alsa-lib
"diaSound.hpp"
posten, ohne Verwendung von "string" in den Funktionen, stattdessen ausschließlich mit " char * " falls möglich ?
Ich schau mal wie ich das umgebaut kriege. String ist doch schon ne deutlich einfachere Sache wie char *. Keine Speicherreservierung usw. Aber ich schaue.
Ich würde sagen, anstelle von zenity verwenden wir ncurse. Sobald ich am Raspi bin (jetzt wieder mit ssh ^^) mach ich mich dran.
ok -
nur wenn du string nimmst, müssen wir ihn sowieso erst in einen Array mit fester Dimension [SHRT_MAX] umkopieren, bevor wir ihn verarbeiten können.
Deine Funktionen bleiben dann aber evtl sogar flexibler.
Nachdem die ersten wav-Tests ja erfolgreich abgeschlossen sind, brauchen wir in Zukunft nur noch mit array input[SHRT_MAX] zu arbeiten, und der zusätzliche array wavebuffer[SHRT_MAX] wird nur noch für wenige Zwischenschritte hilfsweise benötigt.
Die wichtigsten nächsten Regie-Funktionen wären also also:
Menü (1) wav file lesen
*.wav-file ---> (über OpenFileDialog) --> string variabel --> fester array input[SHRT_MAX] mit wav-Header
edit: --> wav-Header herausschneiden (--> array wavebuffer[SHRT_MAX] als Puffer),
--> array input[SHRT_MAX]==reine sound-data zur Weiterverarbeitung
Menü (2) wav file abspielen
*.wav-file ---> (über OpenFileDialog) --> ohne Veränderung direkt über SoundCard abspielen
Menü (3) per Micro aufnehmen
Micro --> direkt --> fester array input[SHRT_MAX]==reine sound-data zur Weiterverarbeitung
Menü (4) akt. Sound (Array im RAM) abspielen + Plot
array input[SHRT_MAX]==reine sound-data direkt über Soundcard abspielen
Menü (5) optimieren
array input[SHRT_MAX] --> noise glätten --> def.Wortgrenzen --> Wort rausschneiden und ganz an den Anfang setzen
(--> array wavebuffer[SHRT_MAX] als Puffer), dann wieder zurückkopieren in
--> array input[SHRT_MAX]==reine sound-data zur Weiterverarbeitung
Menü (6) Sound als *.wav File speichern unter:
array wavebuffer[SHRT_MAX]: an den Anfang den wav-Header, dann direkt anschließend input[SHRT_MAX]
--> wavebuffer[SHRT_MAX] an SaveFileDialog ---> neuen Speichernamen eingeben
--> als *.wav file speichern
Damit wäre es sofort auch am einfachsten für dich, Wortmuster für den FFT-Vergleich aufzunehmen (Micro), zu bearbeiten, und neu zu speichern. Oder bereits vorhandene *.wav Dateien zu öffnen, nachzubearbeiten oder zu überschreiben.
0 Soundfile *.csv in Programm öffnen / laden (FileOpenDialog)
1 Soundfile *.wav in Programm öffnen / laden (FileOpenDialog)
2 Soundfile *.wav öffnen / abspielen + Plot (FileOpenDialog)
3 Sound aufnehmen per Micro / SoundCard
4 akt. Sound (Array im RAM) abspielen + Plot
5 akt. Sound optimieren (noise/cut)
6 akt. Sound (im RAM) als *.wav File speichern unter... (FileSaveDialog)
7 akt. Sound an FFT + Plot
8 akt. Sound cross correlation mit 1 wav File (FileOpenDialog)
9 akt. Sound cross correlation mit allen *.wav Files (auto)
Was machst du nur mit mir? Ich wollte doch nur eine Spracherkennung und bastele jetzt wie ein kleines Kind zu Weihnachten ein altes DOS Menü nach ^^. Es geht voran! Ich habs auch bald. Ein Bild häng ich mal dran.
für die Spracherkennung brauchst du doch jede Menge Vergleichsdaten, und die müssen nunmal möglichst optimal sein.
Die FFT kann ja auch nur vergleichen, was in etwa vergleichbar ist.
Schlechte Basisdaten => falsche Ergebnisse.
Da du ja deine Vergleichsdatenbank erstmal selber per Micro aufnehmen und dann analysieren und optimieren musst, und das Wort für Wort mit wiederkehrenden Algorithmen, alle nach dem selben Muster erstellt, bietet sich doch ein Menü mit diesen festen Regiefunktionen geradezu an, oder nicht? 8)
Ich sage es mal so. Als jemand der gerne im Terminal arbeitet wäre meine Antwort eigentlich
da sich das Menü sehr einfach durch Startparameter umgehen lässt. Wie der Zufall aber nun mal so spielt musste ich, um mein System auf dem neuen Motherboard wieder ins laufen zu bringen, eine RescueCD verwenden. Da ich keine hatte und CDs ja echt out sind, habe ich das Ganze natürlich auf einen USB-Stick gemacht. Das mache ich normalerweise mit dd, wo ich dann einfach das iso auf den Stick schiebe. Aber bei der war ein install dabei. Okay versuche ich mal. Schau an, da war ein Menü im Terminal und sofort musste ich an dich denken. Mal kurz nach geforscht wie das erstellt wurde und so auf Ncurses gestolpert.Code:Nö
Und das hat mich so gereizt das ich da jetzt am bauen bin. So kommt die Jungfrau zum Kind, nichwahr?
Ah um das zu compilieren brauchst du libncurses-dev (glaube ich). Kannst ja mal im Packetmanager schauen. In geany muss noch
dazu.Code:-lncurses
ogott - bitte nicht ncurses! O.o
Zenity ist doch perfekt!
und das Menü sind doch nur 10 zeilen, zur Abfrage einfach auf Tasteneingabe mit Enter warten!
Und ich will doch nicht jedesmal das Programm neu starten mit verschiedenen Parametern, für einfache wiederkehrende Funktionen - viel zu viel Aufwand und viel zu unflexibel !
wav sound bearbeiten muss interaktiv im Programm selber möglich sein!
Ich bin ja schon am Bauen also ganz ruhig! Und ja ncurses. Find ich grade voll lustig. Macht mir Spass.
Es gibt aber grundlegende Unterschiede in der Auffassung. Was du Aufwand nennst finde ich einfach schneller und praktischer.
ich habe einfach Berührungsängste was Monsterlibs angeht und möchte so was nur in äußersten, unumgänglichen Notfällen installieren - die sehe ich hier allerdings nicht wirklich: was soll ncurses können, was normale printf/sprintf-Befehle nicht können?
- - - Aktualisiert - - -
Die Menüabfrage ist ja auch total simpel:
Code:// Terminal: move cursor
#define cursup "\033[A"
#define curshome "\033[0;0H"
#define cls_cons "\033[2J"
FILE * fp;
int32_t input[];
void printMenu() {
printf( cls_cons );
printf( curshome );
printf(" \n
0 Soundfile *.csv in Programm öffnen / laden \n
1 Soundfile *.wav in Programm öffnen / laden \n
2 Soundfile *.wav öffnen / abspielen + Plot \n
3 Sound aufnehmen per Micro / SoundCard \n
4 akt. Sound (Array im RAM) abspielen + Plot \n
5 akt. Sound optimieren (noise/cut) \n
6 akt. Sound (im RAM) als *.wav File speichern unter... \n
7 akt. Sound an FFT + Plot \n
8 akt. Sound cross correlation mit 1 wav File \n
9 akt. Sound cross correlation mit allen *.wav Files (auto) \n\n
q Quit \n\n"
}
int main() {
//...init dies
//...init das
int ch='\0';
while (ch!='q') {
ch='\0';
printMenu();
ch=getchar();
if ch=='q' exit(0);
else
if ch=='0' {fp=FileOpenDialog("*.csv"); // wrapper um popen mit Zenity
getArrayfromFile(input, SHRT_MAX, fp); }
else
if ch=='1' { fp=FileOpenDialog("*.wav"); // wrapper um popen mit Zenity
getArrayfromFile(input, SHRT_MAX, fp);
eraseWavHeader(input, SHRT_MAX); }
else
if ch=='2' { fp=FileOpenDialog("*.wav");
playWaveFile( fp ); // wrapper um popen mit Zenity
plotArray(input, SHRT_MAX ); }
else
if ch=='3' {recordArray(input, SHRT_MAX ); } // von Micro
else
if ch=='4' {playArray(input, SHRT_MAX );
plotArray(input, SHRT_MAX ); }
else
if ch=='5' {optimizeArray(input, SHRT_MAX); // (Nachfolger von analyseArray)
plotArray(input, SHRT_MAX ); }
else
if ch=='6' {buildWavFileArray(input, waveBuffer, SHRT_MAX ); // wav Header vor das Wort setzen
FileSaveDialog(fp, "*.wav"); } // wrapper um popen mit Zenity, als wav file speichern
else
if ch=='7' {;} // FFT, folgt
else
if ch=='8' {;} // FFT, folgt
else
if ch=='9' {;} // FFT, folgt
}
}
ncurses kann menüs mit tastaturnavigation bereitstellen, schonmal versuch tastatureingaben sauber abzufangen und dann in nagivation umzusetzen !? glaub mir, da bricht man sich deutlich mehr einen dran ab als mit tinyalsa :P
und menüs im stil "eingabe 1-10" die dann den ganzen bildschirm dauernd scrollen lassen sind schon ein augenschmerz, da lob ich mir ein halbwegs festehendes Fenster
ABER .. das ist mal wieder eine Geschmacksfrage und über Geschmack streitet man sich nicht, ich kann zumindest die Argumentation von Hirnfrei insoweit verstehen.
PS: Berührungsängste sind die Ängste die man unbedingt überwinden muss!
Ohne Berühung keine Chance für Erfolg oder Misserfolg,
ohne Erfolg oder Misserfolg keine Erfahrung,
ohne Erfahrung kein Fortschritt
PPS: Auf ewig alten Schienen fahren lohnt sich nicht, man muss auch mal ein wenig anderen Menschen (oder deren Code) vertrauen entgegen bringen, vor allem wenn es zum Standard geworden ist ... auch ich zähle mich mittlerweilen was den Programmierstil angeht zu den ewig alten und muss zusehen dass ich bei den ganzen Biliotheken für Dinge die ich mal Bare Metal programmiert habe anpasse und das Rad nicht jedes mal neu erfinde.
ja, wenn wir jetzt Super-Menüs bräuchten: verstehe ich ja.
Brauchen wir aber gar nicht.
ch=getchar() reicht, es müssen ja nur wenige Standardfunktionen wiederholt aufgerufen werden können,
um eine kleine wav-Datenbank zu erstellen und deren sounds zu optimieren,
und um dann, wenn man sie hat,
aktuelle wav-arrays mit dieser Datenbank cross-correlieren zu können.
Die wrapper um popen mit Zenity sind dann allerdings wirklich Gold wert.
ps,
#define cursup "\033[A"
#define curshome "\033[0;0H"
#define cls_cons "\033[2J"
stellt übrigens das Menü auf dem Screen zur Verfügung, ohne zu scrollen (s. Code oben) 8)
und da handle ich nach dem Motto "KISS" ;)
Monstelibs? Ncurses müsste dir eigentlich gefallen weil es echt super einfach ist!
Du musst da aber keine Berührungsängste haben, ich mach das ja. Du benutzt es dann einfach nur, mehr nicht.
Ich sehe gar keine Notwendigkeit für ein Menü, da es auch problemlos über eine Terminaleingabe geht ;).Zitat:
...möchte so was nur in äußersten, unumgänglichen Notfällen installieren - die sehe ich hier allerdings nicht wirklich
ich brauche leider für weitere Versuche auf jeden Fall die integrierte Regiefunktion mit Menü, da ich nie per Kommandozeile arbeite.Zitat:
Ich sehe gar keine Notwendigkeit für ein Menü, da es auch problemlos über eine Terminaleingabe geht
Außerdem müssen mehrere Schritte mit demselben Array im Speicher durchgeführt werden, plus zusätzliche Dateioperationen, und die Arrays im RAM sind ja weg beim Neustart - das wirst du auch merken, wenn wir soweit sind.
Das Menü habe ich dir oben aber ja bereits gepostet, es muss nur einfach in dein Programm mit rein.
Ich fürchte nur fast nach deinem Post:
dir ist noch nicht gar nicht klar, was als nächstes alles gemacht werden muss... ;)
Aber zurück zur Roadmap:
hast du denn inzwischen die ersten 3 Musterwörter erstellt (aufgenommen, "bereinigt", Rausch-Grenzen weggeschnitten, und dann gespeichert) ?
Und existiert inzwischen eine Funktion saveArray, die einen Array im RAM als *.wav file samt header speichert?
Doch ist mir klar nur glaube ich dir ist noch nicht ganz klar wie mächtig die Eingabeaufforderung ist.
Du bekommst ja auch dein Menü, lass mich einfach nur machen.
Nein. Baue noch am Menü. Leider verschlingt die Familie doch ziemlich viel Zeit. Wenn ich ans Programmieren komme ist es oft schon nach 22 Uhr.
es ist nicht "mein Menü", mit dem müssen wir beide arbeiten, ggf. synchron oder per "handshake".
Deshalb mache ich das ja. Wie gesagt, ich selbst könnte ohne, aber da sich das ja mittlerweile zu einem Gemeinschaftsprojekt entwickelt hat bastel ich eben da das Menü. Das mich ncurses da jetzt so heiss gemacht hat konnte ich ja nicht wissen. Finde die Möglichkeiten und die Schlichtheit aber super und kommt so bisschen DOS Feeling auf.