ARDUINO E VOCE

Purtroppo ho il vizio di non leggere tutto fino in fondo ma di andare un po' a grandi passi anche per il tempo che è sempre più tiranno.
Ora rileggendo un po' meglio, ma hai fatto un trattato per gestire input ed output veramente degno di plauso. Ora quando il tempo me lo permette lo leggerò più attentamente. Grazie
paolo

@magpa
Che microfono usi? Quale circuito usi? L'Arduino legge solo tensioni tra 0 e 5V, niente tensioni negative.
Una basetta con MAX4466 e relativo microfonino dovrebbe andare bene.

@docdoc
tra gli esempi della libreria TMRpcm ce n'è uno che scrive i dati acquisiti sulla SD.

Ciao zoomx scusa il ritardo della risposta ma sono stato fuori in altre faccende affaccendato. Ritorno ora a trattare la voce con arduino.
Si uso un micro del genere che menzioni tu ma campionando la voce a 8khz, inviandola poi tramite wifi e risentirla al telefono non è un granchè. Sinceramenteavrei necessità di 2 certezze: primo campionando il segnale in UINT_16 audio = analogread(A0) e poi replicarlo sul telefono.

UINT_16 value = analogread(A0)
audioBuffer[i++] = value & 0xff;
audioBuffer[i++] = value >>8 & 0xff

l'audio buffer lo trasferisco verso il telefono dove un app me lo memorizza in file wav

Risentendo il file wav con cool edit c'è un ronzio di fondo e poi la voce non è così intellegibile

So che le info che ti sto dando non sono molto dettagliate, ma sapresti ugualmente darmi qualche suggerimento?

Ho tentato di far girare l'app Recording del TMRpcm ma su arduino UNO e su arduino nano mi da dei problemi di compilazione

Grazie in anticipo del tuo tempo.
Ciao
paolo

Il ronzio penso sia dovuto all'alimentazione di Arduino se collegato al PC via USB.
In ogni caso su Arduino ci sono diverse fonti di interferenze, potrebbe anche essere la trasmissione via wifi. Se usi UDP può anche essere che si perde qualche pacchetto ma in sostanza il succo è che per adesso non sembra che Arduino sia adatto per un compito del genere.
Esistono però delle shield audio, così come altre board, come la costosa Teensy che ha uno shield audio e dietro una persona, quello che la produce, che la supporta bene.

Quello che vorrei fare è prendere un audio da un altoparlante e tramite esp8266 dopo campionamento inviarlo in wifi verso un app di un telefono che potrebbe replicarla. Sto praticamente impazzendo a trasferire questi campioni in wifi sia per lentezza di timing sia per motivi che alcune volte non capisco nemmeno. Che tu sappia ci sono schede che potrebbero fare questo?

paolo

Non ho trovato microfoni che funzionino in WiFi, solo wireless.

Su ESP8266 ho trovato alcuni link
https://perso.aquilenet.fr/~sven337/english/2016/07/14/DIY-wifi-baby-monitor.html
ma alla fine c'è scritto che è rumoroso

The ESP8266 is not a perfect fit for a project like that : it doesn’t have a decent ADC, it doesn’t have a decent DAC, and it tends to be electrically noisy in such a way that the electret pickup circuit can be affected by wifi transfers. On the other hand it’s cheap, easy to use, and has plenty of processing power.

https://www.esp8266.com/viewtopic.php?f=6&t=11427
ma fa uso di un STM32 oltre all'esp8266

ma lo sketch va modificato perché tìinefficiente.

Forse la soluzione più semplice sarebbe quella di usare un vecchio smartphone.

Qualcosa sono riuscito a fare. Ricevo sufficientemente bene ossia si capisce ma va a scatti. Utilizzo per lo speech sul telefono android AudioTrack che però non so rendere continuo. Sto cercando su Internet, ma senza successo. Eppure di streaming se ne fanno sui telefoni. POssibile che a nessuno è venuto di realizzare uno streaming in casa?

Un'altra cosa che mi capita è che l'ESP qualche volta va lentissimo nella audioclient.write(). La scrittura sul client non schioda qualche volta per 1-2 sec. Lo ricarico e qualche volta riparte ma non sempre. Potrebbe dipendere da chi riceve che essendo piuttosto lento rallenta anche il mittente?

Ti tengo aggiornato se aggiornamenti ci saranno
Ciao
paolo

Lo streaming si fa usando il traffico UDP non TCP, come mi è sembrato di capire.
Significa che chi manda i pacchetti non si cura se arrivino o meno ma spara in continuazione.

Ho trovato degli esempi cercando Walkie Talkie invece di streaming
Questo è per Proton (Broadcom BCM43362 Wi-Fi chip+STM32F205 120Mhz ARM Cortex M )

Questo invece usa ESP8266 ma ha anche lui problemi

Tieni conto che alcuni dei problemi sono dovuti al fatto che anche come ricevitore viene usato un dispositivo analogo e l'ESP8266 non ha un DAC, però ha un'uscita I2S che è poi quella usata dai ricevitori di web radio in streaming.

Poi c'è una libreria che fa uso del chip nRF24L01 che va sui 2.4GHz ma usa un protocollo tutto suo, purtroppo.

Un RaspberryPI 3B+ potrebbe farlo ma non ha ingresso audio, devi usare una scheda audio USB, ma ha il WiFi al contrario dei precedenti modelli.

Grazie dei suggerimenti ma con UDP sembra si perda il 90% dei pacchetti. Esp8266 spedisce alla grande ma il telefono ne prende uno ogni tanto. In effetti sono parecchi al secondo.
Sono ritornato al socket e ieri sera è andato alla grande mi sono sentito la radio la telefono. Grandioso.
Dopo tutte le prove che avevo fatto ho salvato subito il tutto. Inutilmente stamani l'ho ripreso e balbettava come al solito. l'ESP8266-12E fa quello che vuole oghi tanto riesce a star dietro alle spedizione altre volte rallenta e sospende proprio l'elaborazione.

Se blocco l'app sul telefono che riceve l'ESP riprende alla grande e va velocissimo.

E' la connessione socket che lo mette in crisi. Cosa si potrebbe fare per guarirlo.

Stando in debug sull'app del telefono e metto un break sulla ricezione e dopo qualche secondo lo tolgo mantiene per qualche secondo un audio perfetto e poi ricomincia a balbettare.

Ieri sera gli girava bene e non ha perso un colpo.

Tra un po' mi sa che mollo. Non ci riesco a fare una cosa stabile e ripetibile. Mi sa che dovrei mettere un mini computer più potente.

Ciao zoomx, mi dispiace no averti dati belle notizie

Da quello che scrivi il problema potrebbe stare nell'app che non è abbastanza veloce per prendere tutti i pacchetti ed elaborarla. Però è anche vero che in rete i pochi progetti che ho visto son sembrati tutti fallimentari proprio su questo punto.

In ogni caso sappi che ho imparato un poco, nel senso che adesso sono un po' più informato.
Può essere che applicherò parte di quanto imparato per trasmettere segnali più lenti, tipo un campionamento a 200Hz o meno.

Ho trovato un ESP più veloce anzi veloce il doppio e sto facendo i primi test e devo dire che catturare la voce ed inviarla su wifi è eccitante e lo fa abbastanza bene. Ora devo pensare a fare il processo inverso ma sto vedendo che è più rognoso tra le varie codifiche audio che si intrecciano tra android, le varie codifiche wav , ESP e circuiteria spicciola.
Staremo a vedere

Hai preso l'ESP32 oppure hai raddoppiato il clock dell'ESP8266?

Ciao Zoomx ho preso l'esp32 ma devo dire che sono deluso dai risultati della trasmissione voce da e verso il telefono. Non riesco ad ottenere un suono decente. Tutti gracchii, voce che prima parte bene e poi si affievolisce e si confonde con il rumore. L'ho provate tutte o quasi ma non riesco ad ottenere quello che credevo abbastanza facile. Sai cos'è secondo me la cosa particolare che il telefono non ragiona a byte ma solo a int, mentre l'invio verso l'esp32 deve essere a byte quindi prima traduzione. L'esp ragiona a int ma spedendo (ho tanti esempi) traduzione in byte arrivato al telefono altra traduzione. Non riesco a dare un taglio preciso a tutto questo.

Forse l'unica che mi va abbastanza bene è la trasmissione dal telefono all'esp32, ma il contrario è disastroso.

hai sotto mano magari qualche esempio di trasmissione di questo tipo? magari non l'ho ancora provato.

Continuo anche se con poco entusiamo a fare qualche altra prova.

A presto

Purtroppo non ho alcun esempio.
La storia byte e int. L'int è, di solito, 2 byte ma dipende dall'architettura della MCU per questo c'è int16_t e uint16_t che sono sicuramente 2 byte.
L'altra seccatura e l'ordine dei byte nell'int (big endian e little endian) che dipende daccapo dall'architettura della MCU e a questo punto della CPU del telefono. Ad esempio se tu mandi il valore decimale 1500 questo va in 2 byte, 05 hex in uno e DC hex nell'altro. Il problema sorge su quale byte viene prima, quindi per alcuni va scritto 05 DC per altri CD 05.
Non sono sicuro però che qui il problema sia questo.

Tieni conto che parlando di audio le sorgenti di disturbo possono essere diverse per cui mi è venuto in mente di provare a trasmettere un'onda sinusoidale sintetica a 440Hz (o altra frequenza) e vedere se dall'altro lato ti arriva la nota giusta.
L'array con i dati te lo puoi generare qui
http://www.daycounter.com/Calculators/Sine-Generator-Calculator.phtml

Buongiorno, spero di non essere arrivato molto tardi.
Mi accodo in quanto anch'io vorrei prelevare un suono mediante un Microfono collegato in analogico al NodeMCU, spedirlo ad un Raspberry o PC e da li gestirlo.

Attualmente acquisisco il suono e lo spedisco via UDP.

Il microfono KY-038, collegato al NodeMCU mediante pin analogico "A0".

Lo Sketch su NodeMCU:

#include <ESP8266WiFi.h> // libreria per la gestione del wifi di ESP
#include <WiFiUdp.h> // libreria per utilizzare i moduli UDP

const char* ssid = "------"; // inserisci SSID della rete wifi a cui si collegherà NodeMCU
const char* password = "------"; // password della rete wifi a cui si collegherà NodeMCU

int contconexion = 0;

WiFiUDP Udp;

void setup()
{
  Serial.begin(115200);
  Serial.println();

  pinMode(5, OUTPUT);  //D1 Led de estado
  digitalWrite(15, LOW);

  WiFi.mode(WIFI_STA); //para que no inicie el SoftAP en el modo normal
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED and contconexion <50) { //Cuenta hasta 50 si no se puede conectar lo cancela
    ++contconexion;
    delay(250);
    Serial.print(".");
    digitalWrite(5, HIGH);
    delay(250);
    digitalWrite(5, LOW);
  }
  
}

void loop()
{
  //Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
  Udp.beginPacket("---.---.---.---", 1234); // indirizzo IP della macchina su cui sta il server

  for(int i=0; i<1024;i++){
    int old=micros();

    float analog = analogRead(17); 

    analog = ((analog / 1) - 385);
    if (analog > 255){
      analog = 255;
    }
    else if (analog < 0){
      analog = 0;
    }
    
    Udp.print(int(analog)); // mando i pacchetti mediante il canale UDP
    
    Serial.println(int(analog)); // visualizzo grafico audio in Plotter seriale

    while(micros()-old<124); // 90uSec = 1Sec/11111Hz - 3uSec para los otros procesos
  }
  Udp.endPacket();
  delay(5);
}

Il Server scritto in Python:

import pyaudio
import socket

UDP_IP = "---.---.---.---" # indirizzo IP della macchina su cui sta il server
UDP_PORT = 1234 # porta che rimane in ascolto

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind((UDP_IP, UDP_PORT))


p = pyaudio.PyAudio()

print("pyaudio: ", p)
stream = p.open(format=32, channels=1, rate=111111, output=True)

print("stream: ", stream)

try:
    while True:
        data, addr = sock.recvfrom(1024) # buffer de 1024 bytes
        print ("data: ", data)
        print ("addr: ", addr) 
        stream.write(data) # mi fa sentire l'audio negli altoparlanti
        
except KeyboardInterrupt:  #precionar Crtl + C para salir
    print("Cerrando...")
    stream.stop_stream()
    stream.close()
    p.terminate()

L'audio che riproduco dagli speaker del PC è completamente distorto e incomprensibile. Visualizzando il Plotter seriale, le oscillazioni si vedono bene.

Deduco possa essere un problema di acquisizione e spedizione pacchetti (visto che la lettura del canale analogico avviene (apparentemente) correttamente).

Intanto stai usando un microfono un po' sordo in quanto pensato per accendere e spegnere qualcosa con un battito di mani.

Poi fai un clipping feroce qui

    analog = ((analog / 1) - 385);
    if (analog > 255){
      analog = 255;
    }
    else if (analog < 0){
      analog = 0;
    }

Dovresti prendere un microfono con un MAX, dalla Cina costa poco più di quello che stai usando.

Potrebbe essere che al prosto di UDP.print dovresti usare UDP.write perché mi sa che print te lo stampa in ascii.

Non ho capito poi questo pezzo di codice (analog / 1)

Grazie per la risposta.

cosa intendi per Clipping feroce?

Per il microfono potrei procurare altro anche se avrei una certa fretta quindi chissà se lo riuscirò a trovare in italia. Ma ti riferisci a qualcosa simile a: MAX4466.
Io ho preso l'idea dal video youtube: Proyecto #1 ESP8266 – Micrófono Espía, Audio Streaming por UDP

Credo utilizzi un sistema microfonico simile anche se la scheda la costruisce lui.

Come potrei impacchettare l'audio? Nel senso, dal video spedisce lo streaming, io invece vorrei campionare a 4000 hz quindi per Nyquist dovrei avere il doppio ovvero 8000 valori. Ho pensato che (1/8000)*1000=0,125 millisecondi ovvero ogni 0,125 millisecondi dovrei leggere 8000 valori, metterli in un vettore e sparare l'intero vettore in UDP. E' corretto il ragionamento?

Ho testato, con:

 Udp.print(int(analog));

o

 Udp.write(int(analog));

la situazione a livello di audio non cambia, cambia solo l'output nel Monitor seriale che come dicevi tu giustamente, visualizza piuttosto che numeri, codici ascii.

Ho ordinato i microfoni da te consigliati (MAX) e di preciso MAX9814 e MAX4466, li ho presi entrambi anche se credo che nel mio caso dovrebbero svolgere la medesima funzione.

Nel frattempo che arrivino (ordinati in Italia per accorciare i tempi) vorrei andare avanti e magari creare i buffer e spedire i buffer via UDP piuttosto che a casaccio quello che passa passa.

NOTA. Strano che nel video passa bene l'audio, il circuito sembra uguale.

Ho visto il video.
Intanto nello sketch c'è

Udp.write(int(analog));

come dicevo io.
Poi il circuiti del microfono è diverso, non usa quella schedina rossa, l'ho usata anche io e non va bene.

Per quanto riguarda il clipping. L'ESP8266 campiona a 10 bit, quindi valori da 0 a 1023. Lo sketch divide il valore per 1, forse prima era qualcosa di diverso ma adesso dividere per 1 non serve.
Quindi sottrae un valore fisso che probabilmente corrisponde alla media dei valori che escono fuori dal convertitore se non c'è alcun segnale.
Poi, se il valore è maggiore di 255 lo tronca a 255.
Infine controlla se con la sottrazione non è andato sotto zero, se si lo porta daccapo a zero.

Il motivo per cui non usa 2 byte è dovuto al fatto che con 2 byte le cose si complicano perché dall'altra parte nel flusso quando prendi 2 byte non sai se appartengono allo stesso campione oppure a due campioni consecutivi. Devi usare un protocollo oppure trasmettere una coppia di byte ogni tanto che servono per sincronizzare i flussi (con UDP i pacchetti possono andare persi e non si ha correzione).

I microfoni che hai preso vanno bene, sono anche quelli che ho usato io. Forse prenderai un po' di rumore lo stesso perché ci sono un sacco di interferenze. Mentre il microfono con la scheda rossa ti fornisce zero se non c'è segnale questi col MAX lavorano come il circuito del video, ti forniranno un valore intorno a 512. Questo perché il convertitore funziona solo con tensioni positive mentre il microfono ne fornisce negative. Quella rossa credo che le elimini, quella con MAX invece somma una tensione positiva in moto da avere sempre valori positivi. Non so se mi son spiegato bene.

Non ho ancora ascoltato il video.

Grazie

zoomx

.

Forse mi manca qualche parte, ma non capisco cosa intendi:

Il motivo per cui non usa 2 byte è dovuto al fatto che con 2 byte le cose si complicano perché dall'altra parte nel flusso quando prendi 2 byte non sai se appartengono allo stesso campione oppure a due campioni consecutivi. Devi usare un protocollo oppure trasmettere una coppia di byte ogni tanto che servono per sincronizzare i flussi (con UDP i pacchetti possono andare persi e non si ha correzione).

Per il discorso del microfono, si infatti mi sembrava strano che lo aveva costruito lui uguale a quello o che quello potesse andar bene, anche perché il codice è molto semplice figurati.

Rimane, lasciando stare il microfono che è stato spedito oggi, il problema di come dovrei passare queste tracce al pc o Raspberry. Io mi vorrei trovare sul pc o Raspberry una traccia wav ad esempio ogni 10 secondi o più di acquisizione.

Pensavo di fare due vettori, ne riempivo uno e lo sparavo, mentre lo sparavo, ne riempivo un altro, in modo ciclico. Tipo swap. Ma non saprei come fare. Penso che lavorando su wav potrei riuscire.

Come avevo scritto:

Ho pensato che (1/8000)*1000=0,125 millisecondi ovvero ogni 0,125 millisecondi dovrei leggere 8000 valori, metterli in un vettore e sparare l'intero vettore in UDP. E' corretto il ragionamento?

dovrei prendere e riempire il vettore con 8000 celle ogni 0,125 millisecondi.. ehmmm..