dann mach doch auch
char * wave;
da gibts sonst immer so hässliche *WARNINGS* vom Compiler ;)
char ist allerdings komisch bei int16 (16bit encoding)
Druckbare Version
dann mach doch auch
char * wave;
da gibts sonst immer so hässliche *WARNINGS* vom Compiler ;)
char ist allerdings komisch bei int16 (16bit encoding)
Ich mag String aber lieber da ich mich da nicht um den Speicher kümmern muss. Zu meinen reinen Ansi-C Zeiten war das immer mein grösstes Problem. Hier mal zu wenig allociert, peng Absturz usw. Das macht String viel viel einfacher.
Und Warnungen stören mich wenig ;)
wenn du deinen wave string gesäubert und entrauscht hast -
dann muss er ja in einen komplexen array kopiert werden (type casting (float), in reelen Teil, imaginärer bleibt leer == 0 ).
Geht das mit string genauso einfach wie mit char[] ?
und wieso jetzt char[] bei int16 (16bit encoding) ?
ps,
übrigens musst du dafür sowieso die array-Größe deines wave arrays festlegen, um es der FFT zu unterwerfen.
char (oder int16_t) wave[SHRT_MAX] // == 32767
wäre also eh die richtige Array-Größe, ohne \0 am Schluss wie bei strings.
Du siehst ja, es kommt ein vector<int> bei der Aufnahme heraus. Was man damit dann letzten Endes macht ist ziemlich egal. Man muss es ja auch nicht mehr aus geben. Es geht ja darum das der Bot versteht was man von ihm will, nicht das er wiederholt was man ihm sagt.
Sagen wir so. Du brauchst für Spracherkennung letzten Endes nur das audioCapture();. Da kommen die Daten und dann wird damit gearbeitet. Da ich noch keinen Plan habe wie FFT überhaupt funktioniert kann ich dazu aber auch nichts sagen. Da du aber da schon Erfahrung hast, wie würdest du denn aus dem ankommenden vector<int> passende Daten für FFT machen?
Hast du eigentlich eine Idee wie man den Scheiss entrauschen kann?
ich kenne mich mit vector <int> gar nicht aus, ich verwende grundsätzlich nur explizite C11 Datentypen
int16_t wavarray[SHRT_MAX]
für die komplexen Zahlen brauchst du die beiden floatarrays
float fx_[USHRT_MAX], fy_[USHRT_MAX]
die muss man erst auf Null setzen
memset(fx_ , 0, sizeof(fx_) ); // reel-Teil
memset(fy_ , 0, sizeof(fy_) ); // imaginär-Teil
dann die ints konvertieren und in die 1. Hälfte der fx_ arrays reinkopieren
for(int i=0; i<SHRT_MAX; ++i) fx_[i] = (float)wavarray[i]; // evtl sogar ein bisschen weniger, damit die 2. Hälfte überwiegt mit 0-Werten,
dann ist der ganze Rest der Komplex-Arrays schon auf Null, wie man es für die cross-correlation braucht.
Jetzt kann man die FFT darauf anwenden.
Bis dahin habe ich es gemacht, und dann abgebrochen, wegen irre langer Laufzeit auf dem NXT.
Übrigens:
für den Raspi würde ich double statt float nehmen, weil er intern auf 64bit double schneller rechnet als mit 32bit float.... 8-)
Die echte Cross-Correlation ist damit ebenfalls Neuland für mich!
entrauschen ist mein Lieblingsthema, das ist über Schwellwerte, Lowpass - und Highpass-Filter möglich, außerdem Spikes abfangen per gleitendem Medianfilter 8-)
(da gibt es aber bestimmt schon super Links dazu im www ;) )
ps,
allerdings geht NICHTS über ein sauber aufgenommenes original-Micro-Signal ! 8-)
vector<int> ist nicht wirklich was anderes wie ein int array. Ich benutze vector sehr gerne da man dann einfach mit push_back() die nächste Variable dran hängen kann. Aber genau genommen ist es einfaches int.
Klar geht nichts über ein sauberes Mikro. Bliebe nur die Frage, was muss ich ändern damit das Mikro nicht rauscht?
- ein wirklich gutes Micro mit der richtigen Impedanz verwenden ;)
- Aufnahmeparameter für den record-Teil optimieren (Empfindlichkeit, Aussteuerung)
- gucken, dass man bei Mono-Aufnahme auch nur die Mono-Spur bekommt zur Weiterverarbeitung (d.h. keine verrauschte ungenutze Stereo-Spur dabei ist)
- die Hintergrund-Umgebungsgeräusche kann man meist ja nicht beeinflussen...
Der Rest ist Signal Glättung mit Statistik-Filtern, da kann man selber experimentieren (s.o.) oder wirklich erstmal schnelle erprobte Lösungen im web suchen.
ps,
wir brauchen kein push-back, aber definierte Arrays mit definierter Größe, ich würde wirklich den definierten int16_t array vorziehen!
Ich nehme mal an, die eigentliche Einstellungen für das Mikrofon muss ich über den Alsa-Mixer machen. Denke ich zumindest mal. Habe jetzt mal noch nicht gesehen wo ich das in meinem Programm beeinflussen können sollte. Mal schauen.
Was ich im Moment erkennen kann, es kommen Zahlen von 0 bis 255 an. Ich fange ich jetzt damit an? Bislang arbeite ich mit 1 Kanal. Sind das dann die Daten von nur diesem einen Kanal?
Was die Variablen angehen, es kommt also ein vector<int> zurück. Da kannst du jetzt alles draus machen was du machen willst.
Mal als Beispiel. Hab das jetzt nicht versucht, aber dürfte so machbar sein.Code:
int16_t waveArray[xxx];
for(i=0;i<input.size();i++)
{
waveArray[i] = input[i];
}
- - - Aktualisiert - - -
So ich habe gebastelte!
Die neue Header Datei:
Die neue MainCode:#include <alsa/asoundlib.h>
#include <iostream>
#include <vector>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <time.h>
using namespace std;
typedef struct _FILE_head
{
unsigned char ID[4];
unsigned int Length;
unsigned char Type[4];
} FILE_head;
typedef struct _FORMAT
{
short wFormatTag;
unsigned short wChannels;
unsigned int dwSamplesPerSec;
unsigned int dwAvgBytesPerSec;
unsigned short wBlockAlign;
unsigned short wBitsPerSample;
} FORMAT;
typedef struct _CHUNK_head
{
unsigned char ID[4];
unsigned int Length;
} CHUNK_head;
snd_pcm_t *soundKarte;
bool Init(string name, unsigned int channels, unsigned int actualRate, unsigned short WaveBits)
{
int err;
snd_pcm_format_t bits;
unsigned int resample = 1;
switch(WaveBits)
{
case 8:
bits = SND_PCM_FORMAT_U8;
break;
case 16:
bits = SND_PCM_FORMAT_S16;
break;
case 24:
bits = SND_PCM_FORMAT_S24;
break;
case 32:
bits = SND_PCM_FORMAT_S32;
break;
}
snd_pcm_hw_params_t *hw_params;
if(name.length() == 0)
{
err = snd_pcm_open(&soundKarte, "plughw:1,0", SND_PCM_STREAM_PLAYBACK, 0);
}
else
{
err = snd_pcm_open(&soundKarte, name.c_str(), SND_PCM_STREAM_PLAYBACK, 0);
}
if(err < 0)
{
cout << "Init: Kann die Soundkarte nicht öffnen! " << name << " (" << snd_strerror (err) << ")" << endl;
return false;
}
if((err = snd_pcm_hw_params_malloc(&hw_params)) < 0)
{
cout << "Init: Parameter können nicht initialisiert werden (" << snd_strerror (err) << ")" << endl;
return false;
}
if((err = snd_pcm_hw_params_any(soundKarte, hw_params)) < 0)
{
cout << "Init: Parameter können nicht ermittelt werden (" << snd_strerror (err) << ")" << endl;
return false;
}
err = snd_pcm_hw_params_set_rate_resample(soundKarte, hw_params, resample);
if(err < 0)
{
cout << "Init: Resampling kann nicht eingeschaltet werden " << snd_strerror(err) << endl;
return err;
}
if((err = snd_pcm_hw_params_set_access(soundKarte, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
{
cout << "Init: Zugriffstyp kann nicht gesetzt werden (" << snd_strerror (err) << ")" << endl;
return false;
}
if((err = snd_pcm_hw_params_set_format(soundKarte, hw_params, bits)) < 0)
{
cout << "Init: Sample-Format kann nicht gesetzt werden (" << snd_strerror (err) << ")" << endl;
return false;
}
if((err = snd_pcm_hw_params_set_channels(soundKarte, hw_params, channels)) < 0)
{
cout << "Init: Anzahl der Kanäle kann nicht gesetzt werden (" << snd_strerror (err) << ")" << endl;
return false;
}
if((err = snd_pcm_hw_params_set_rate_near(soundKarte, hw_params, &actualRate, 0)) < 0)
{
cout << "Init: Sample-Rate kann nicht auf " << actualRate << " gesetzt werden (" << snd_strerror (err) << ")" << endl;
return false;
}
if((err = snd_pcm_hw_params(soundKarte, hw_params)) < 0)
{
cout << "Init: Parameters können nicht gesetzt werden(" << snd_strerror (err) << ")" << endl;
return false;
}
snd_pcm_hw_params_free(hw_params);
if((err = snd_pcm_prepare(soundKarte)) < 0)
{
cout << "Init: Audio kann nicht zur Nutzung vorbereitet werden (" << snd_strerror (err) << ")" << endl;
return false;
}
return true;
}
bool InitCapture(string name, unsigned int channels, unsigned int actualRate, unsigned short WaveBits)
{
int err;
snd_pcm_format_t bits;
switch(WaveBits)
{
case 8:
bits = SND_PCM_FORMAT_U8;
break;
case 16:
bits = SND_PCM_FORMAT_S16;
break;
case 24:
bits = SND_PCM_FORMAT_S24;
break;
case 32:
bits = SND_PCM_FORMAT_S32;
break;
}
snd_pcm_hw_params_t *hw_params;
if(name.length() == 0)
{
err = snd_pcm_open(&soundKarte, "plughw:1,0", SND_PCM_STREAM_CAPTURE, 0);
}
else
{
err = snd_pcm_open(&soundKarte, name.c_str(), SND_PCM_STREAM_CAPTURE, 0);
}
if(err < 0)
{
cout << "Init: Kann die Soundkarte nicht öffnen! " << name << " (" << snd_strerror (err) << ")" << endl;
return false;
}
if((err = snd_pcm_hw_params_malloc(&hw_params)) < 0)
{
cout << "Init: Parameter können nicht initialisiert werden (" << snd_strerror (err) << ")" << endl;
return false;
}
if((err = snd_pcm_hw_params_any(soundKarte, hw_params)) < 0)
{
cout << "Init: Parameter können nicht ermittelt werden (" << snd_strerror (err) << ")" << endl;
return false;
}
if((err = snd_pcm_hw_params_set_access(soundKarte, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
{
cout << "Init: Zugriffstyp kann nicht gesetzt werden (" << snd_strerror (err) << ")" << endl;
return false;
}
if((err = snd_pcm_hw_params_set_format(soundKarte, hw_params, bits)) < 0)
{
cout << "Init: Sample-Format kann nicht gesetzt werden (" << snd_strerror (err) << ")" << endl;
return false;
}
if((err = snd_pcm_hw_params_set_channels(soundKarte, hw_params, channels)) < 0)
{
cout << "Init: Anzahl der Kanäle kann nicht gesetzt werden (" << snd_strerror (err) << ")" << endl;
return false;
}
if((err = snd_pcm_hw_params_set_rate_near(soundKarte, hw_params, &actualRate, 0)) < 0)
{
cout << "Init: Sample-Rate kann nicht auf " << actualRate << " gesetzt werden (" << snd_strerror (err) << ")" << endl;
return false;
}
if((err = snd_pcm_hw_params(soundKarte, hw_params)) < 0)
{
cout << "Init: Parameters können nicht gesetzt werden(" << snd_strerror (err) << ")" << endl;
return false;
}
snd_pcm_hw_params_free(hw_params);
if((err = snd_pcm_prepare(soundKarte)) < 0)
{
cout << "Init: Audio kann nicht zur Nutzung vorbereitet werden (" << snd_strerror (err) << ")" << endl;
return false;
}
return true;
}
bool UnInit()
{
snd_pcm_close(soundKarte);
return true;
}
int playwave(string waveDatei, string name)
{
FORMAT format;
FILE_head head;
CHUNK_head chead;
char *wave;
register snd_pcm_uframes_t count, frames;
int datei;
unsigned int WaveSize;
datei = open(waveDatei.c_str(), 00);
read(datei, &head, sizeof(FILE_head));
read(datei, &chead, sizeof(CHUNK_head));
read(datei, &format, sizeof(FORMAT));
wave = (char *) malloc(head.Length);
read(datei, wave, head.Length);
WaveSize = head.Length * 8 / ((unsigned int)format.wBitsPerSample * (unsigned int)format.wChannels);
close(datei);
Init(name, format.wChannels, format.dwSamplesPerSec, format.wBitsPerSample);
count = 0;
do
{
frames = snd_pcm_writei(soundKarte, wave + count, WaveSize - count);
if (frames < 0) frames = snd_pcm_recover(soundKarte, frames, 0);
if (frames < 0)
{
printf("Kann wav nicht abspielen: %s\n", snd_strerror(frames));
break;
}
count += frames;
} while (count < WaveSize);
if (count == WaveSize) snd_pcm_drain(soundKarte);
free(wave);
UnInit();
return 0;
}
vector<int> audioCapture(int sek, string name, unsigned int channels, unsigned int actualRate, unsigned short WaveBits)
{
int err, zielzeit;
char *puffer;
vector<int> input;
time_t t;
t = time(NULL);
zielzeit = t + sek;
puffer = (char *) malloc(1);
cout << "Beginne Aufnahme von " << sek << " Sekunden!" << endl;
if(InitCapture(name, channels, actualRate, WaveBits))
{
while(t < zielzeit)
{
err = snd_pcm_readi(soundKarte, puffer, 1);
if(err < 0) cout << "Fehler bei der Aufnahme!" << endl;
input.push_back(puffer[0]);
t = time(NULL);
}
UnInit();
}
else cout << "Bei der Initialisierung ist ein Fehler aufgetreten!" << endl;
cout << "Aufnahme beendet!" << endl;
return input;
}
void playCaptured(char *wave, unsigned int WaveSize, string name, unsigned int channels, unsigned int actualRate, unsigned short WaveBits)
{
register snd_pcm_uframes_t count, frames;
Init(name, channels, actualRate, WaveBits);
WaveSize = WaveSize * 8 / WaveBits * channels;
count = 0;
// for(int i=0;i<WaveSize-2;i++) printf("%d/%d -> %d\n", i, WaveSize, wave[i]);
do
{
frames = snd_pcm_writei(soundKarte, wave + count, WaveSize - count);
if(frames < 0) frames = snd_pcm_recover(soundKarte, frames, 0);
if(frames < 0)
{
printf("Kann wav nicht abspielen: %s\n", snd_strerror(frames));
break;
}
count += frames;
} while (count < WaveSize);
if (count == WaveSize) snd_pcm_drain(soundKarte);
UnInit();
}
Habe es jetzt extra für dich auf char * umgestellt ;).Code:#include <iostream>
#include <vector>
#include <stdio.h>
#include "diaSound.hpp"
int main()
{
vector<int> input;
unsigned int i;
char *wave;
input = audioCapture(5, "plughw:1,0", 1, 44100, 8);
wave = (char *) malloc(input.size());
for(i=0;i<input.size();i++)
{
wave[i] = input[i];
}
playCaptured(wave, input.size(), "plughw:1,0", 1, 44100, 8);
free(wave);
return 1;
}
Interessant ist, bei 16 Bit rauscht es ohne Ende. Bei 32 Bit kommt überhaupt kein Sound, bei 8 Bit ist leichtes Rauschen und man hört das was man in das Mikro rein spricht ^^. Wieder ein Punkt erledigt.
Jetzt geht es weiter!
wie wav files kodiert sind, weiß ich nicht, ich habe ja nur mit Lautstärke-Schwankungen experimentiert.
Dass Werte von 0...255 ankommen wundert mich nicht, aber ich vermute, die sind gruppiert in int16-Blöcke (bei 16-bit-sampling), einmal rechter und einmal linker Kanal.
wenn du allerdings mit 8 bit sampelst, sind es sicher einzelne Bytes, nicht int16.
Bei ausschließlicher Verwendung von expliziten Datentypen hat man übrigens noch einen enormen Geschwindigkeitsvorteil
(int32_t ist auch hier beim Raspi schneller als int16_t).
sind nämlich sowohl wave als auch input vom selben Typ (switchen wir ruhig mal auf int32_t, das ist ja mit int auf ARMs meist identisch ...)
int32_t wave[FESTE_LAENGE], input[FESTE_LAENGE];
dann ist das hier nämlich -zigmal schneller als iterativ einzelne Zellen rüberzukopieren...:
memcpy(wave, input, sizeof(input) );
Was mir aufgefallen ist, wenn das Mikro wenig oder gar keine Geräusche wahr nimmt ist der Wert in der Regel um die 128 herum. Gehe ich davon aus das es sich dabei so gesehen um die 0 Linie handelt?
Interessant dürfte aber auch sein, kann man mit einer Soundkarte auch wirklich von zwei Mikros Stereo aufnehmen? Das wäre bei einem Bot schon sinnvoll da man damit auch mehr oder weniger orten könnte von wo das Geräusch kommt.