Ich arbeite an einem Projekt, bei dem ich (einfachen) Klang erzeugen möchte, indem ich verschiedene Sinuswellen kombiniere. Ich benutze ein Arduino mkrZero, da es I2S-Schnittstelle eingebaut hat und es scheint genug Rechenleistung für das zu haben, was ich will.Arduino I2S Sinuswelle
ich mein System genau verdrahtet wie im Tutorial für Arduino I2S simpleTone:
Und der tutorial Code funktioniert gut, und ich bekomme eine einfache Rechteckwelle Ton aus dem Lautsprecher.
Jetzt habe ich den Code modifizierte Sinuswelle zu erzeugen, gibt es eine Lookup-Tabelle für die sin-Funktion es schnell genug zu machen:
#include <I2S.h>
uint16_t isin16[] = {
0, 1144, 2287, 3430, 4571, 5712, 6850, 7987, 9121, 10252, 11380,
12505, 13625, 14742, 15854, 16962, 18064, 19161, 20251, 21336, 22414,
23486, 24550, 25607, 26655, 27696, 28729, 29752, 30767, 31772, 32768,
33753, 34728, 35693, 36647, 37589, 38521, 39440, 40347, 41243, 42125,
42995, 43851, 44695, 45524, 46340, 47142, 47929, 48702, 49460, 50203,
50930, 51642, 52339, 53019, 53683, 54331, 54962, 55577, 56174, 56755,
57318, 57864, 58392, 58902, 59395, 59869, 60325, 60763, 61182, 61583,
61965, 62327, 62671, 62996, 63302, 63588, 63855, 64103, 64331, 64539,
64728, 64897, 65047, 65176, 65286, 65375, 65445, 65495, 65525, 65535,
}; //0-90
const int sincount = 2;
int freqs[] = {50*360,51*360};
float amps[] ={0.1,0.1};
const int sampleRate = 8000; // sample rate in Hz
short sample = 0;
double t = 0;
double dt = 1.0/(1.0*sampleRate);
short LR[] = {0,0};
void setup() {
Serial.begin(115200);
// start I2S at the sample rate with 16-bits per sample
if (!I2S.begin(I2S_PHILIPS_MODE, sampleRate, 16)) {
while (1); // do nothing
}
}
void loop() {
sample = 0;
for(int n= 0;n<sincount;n++)
{
sample += fSin(freqs[n]*t)*amps[n];
}
t += dt;
LR[0] = sample;
LR[1] = sample;
I2S.write(LR[0]);//left channel
I2S.write(LR[1]);//right channel
}
float fSin(long x)
{
boolean pos = true; // positive - keeps an eye on the sign.
if (x < 0)
{
x = -x;
pos = false;
}
if (x >= 360) x %= 360;
if (x > 180)
{
x -= 180;
pos = !pos;
}
if (x > 90) x = 180 - x;
if (pos) return isin16[x]; // = /65535.0
return isin16[x];
}
Dies funktioniert auch gut.
ABER!
Wenn ich den Code ein wenig ändern und ich schreibe
I2S.write(LR,2);
statt
I2S.write(LR[0]);//left channel
I2S.write(LR[1]);//right channel
Alles nur bricht, klingt der Ton aus dem Lautsprecher wie ein horrible scream
Von der I2S-Bibliotheksreferenz:
Beschreibung
Schreibt binäre Daten an die I2S-Schnittstelle. Diese Daten werden als eine Probe oder eine Reihe von Proben gesendet.
Syntax
I2S.write(val)
// Blockierung
I2S.write(buf, len)
// nicht blockiert
Parameter
val: ein Wert als eine einzige Probe zu senden
buf :
len ein Array als eine Reihe von Proben zu senden: die Länge des Puffers
Returns
Byte-write() wird die Anzahl der Bytes zurück geschrieben, wenn das Lesen diese Anzahl ist optional .
Ich würde gerne die letztere Version der Schreibfunktion verwenden, weil sie nicht blockiert und ich kann neue Samples erzeugen, während die vorherigen spielen.
Irgendwelche Ideen, wie die gepufferte Version funktioniert auch?