Old Fidelity - HiFi Klassiker Forum

Normale Version: Digitales VU-Meter (Mikrocontroller, Display, LED) reVox A700
Du siehst gerade eine vereinfachte Darstellung unserer Inhalte. Normale Ansicht mit richtiger Formatierung.

DIYLAB

Keine Ahnung was hier falsch läuft, im Ringpuffer landen nur negative Zahlen  Denker .

Code:
  // Fill circular buffers.
    circularBufferLeft.push(2 * peak1.read() - 1);
    circularBufferRight.push(2 * peak2.read() - 1);

Der Puffer ist double.

Code:
// Global vars
CircularBuffer<double, 2048> circularBufferLeft;
CircularBuffer<double, 2048> circularBufferRight;

gogosch

Amplitude zu gering?
Steht am peak-Ausgang vom Teensy Audio-Shield wirklich der tatsächliche Sample-Wert oder nur ein Wert für die Amplitude?

DIYLAB

(04.09.2020, 17:26)gogosch schrieb: [ -> ]Amplitude zu gering?
Steht am peak-Ausgang vom Teensy Audio-Shield wirklich der tatsächliche Sample-Wert oder nur ein Wert für die Amplitude?

Wird wohl wirklich die Amplitude sein, die zu gering ist.
Zu Deiner zweiten Frage, es ist leider nicht der Samplewert, sondern schon aufbereitet.
Du findest in der Audiolib die Klasse AudioAnalyzePeak, die von AudioStream erbt, dort ist dann read zu finden.

Code:
class AudioAnalyzePeak : public AudioStream
{
public:
    AudioAnalyzePeak(void) : AudioStream(1, inputQueueArray) {
        min_sample = 32767;
        max_sample = -32768;
    }
    bool available(void) {
        __disable_irq();
        bool flag = new_output;
        if (flag) new_output = false;
        __enable_irq();
        return flag;
    }
    float read(void) {
        __disable_irq();
        int min = min_sample;
        int max = max_sample;
        min_sample = 32767;
        max_sample = -32768;
        __enable_irq();
        min = abs(min);
        max = abs(max);
        if (min > max) max = min;
        return (float)max / 32767.0f;
    }
    float readPeakToPeak(void) {
        __disable_irq();
        int min = min_sample;
        int max = max_sample;
        min_sample = 32767;
        max_sample = -32768;
        __enable_irq();
        return (float)(max - min) / 32767.0f;
    }

    virtual void update(void);
private:
    audio_block_t *inputQueueArray[1];
    volatile bool new_output;
    int16_t min_sample;
    int16_t max_sample;
};
nee, das .NET 3.5 isses nich. War bei mir schon installiert...
Aber auf dem Läppi läuft alles. Seltsam - sonst ist das eher umgekehrt und der T60 macht Sperenzchen Denker

(04.09.2020, 15:34)DIYLAB schrieb: [ -> ]
(04.09.2020, 15:23)havox schrieb: [ -> ]Und bei Dir läuft doch auch der Realtek Treiber und da geht's? Merkwürdig.

Ich habe da noch eine ganz blöde Vermutung.
Mein Programm ist ja mit .NET 4.7.2 Compiliert (sollte jeder Windows 10 PC haben).
NAudio, also die Audio-Library, ist allerdings vom Hersteller aus mit .NET 3.5 compiliert und ich bekomme sein Projekt auch nicht unter 4.7.2 compiliert).
.NET 3.5 ist aber kein fester Bestandteil von Windows 10.
Normalerweise sollten die neueren Bibliotheken ja abwärts kompatibel sein, aber wer weiß?
Da ich aber schon seit Ewigkeiten bei Windows 10 .NET 3.5 installiere (brauche ich teilweise für  ältere Projekte), fällt es mir gar nicht auf, wen es fehlt.
Installiere doch mal testweise .NET 3.5 nach, vielleicht hilfts?

Aber wie auch immer, ich hänge mit dem Problem am Teensy aus meinem letzten Posting fest.
Wenn wir das nicht lösen können, dann ist Schicht im Schacht.

LG

DIYLAB

(04.09.2020, 19:20)DIYLAB schrieb: [ -> ]Zu Deiner zweiten Frage, es ist leider nicht der Samplewert, sondern schon aufbereitet.

Einen Schritt weiter ...
Die Idee mit dem Peak war schrottig.
Der Ringpuffer ist schon eine feine Sache, ist aber auch wieder rausgeflogen.
Jetzt benutze ich AudioRecordQueue für beide Kanäle und zwei 2048er int16 Arrays als Puffer.
Die Puffer füllen sich regelmäßig, wenn die Queues die Samples zusammen haben.
Das klappt soweit, die Puffer füllen sich Tatsache und stehen für das ganze Projekt zur Verfügung.
Jetzt muss ich aus den Werten noch etwas sinnvolles generieren  Denker

By(te),
Bruno

DIYLAB

Man ist das alles ein schlecht dokumentierter Salat.
Ich werde aus dem RecordQueue nicht schlau.
Beinhaltet der nun beide Kanäle oder nicht?
Braucht Keiner zu antworten, ich denke nur laut  Floet .
LG

gogosch

(04.09.2020, 22:45)DIYLAB schrieb: [ -> ]Man ist das alles ein schlecht dokumentierter Salat.
Ich werde aus dem RecordQueue nicht schlau.
Beinhaltet der nun beide Kanäle oder nicht?
Braucht Keiner zu antworten, ich denke nur laut  Floet .
LG

Es werden beide Kanäle (paarweise) via readBuffer() ausgegeben.

DIYLAB

(05.09.2020, 08:50)gogosch schrieb: [ -> ]Es werden beide Kanäle (paarweise) via readBuffer() ausgegeben.

Wo kann man das nachlesen?

gogosch

(05.09.2020, 08:51)DIYLAB schrieb: [ -> ]
(05.09.2020, 08:50)gogosch schrieb: [ -> ]Es werden beide Kanäle (paarweise) via readBuffer() ausgegeben.

Wo kann man das nachlesen?

... es gibt für die Teensy Audio Lib einige Beispiele z.B. für "Recording auf SD-Karte". Da wird nur eine recordQueue verwendet. Ich nehme an dass dies nicht nur ein Mono-Signal umfasst. Überall wird nur eine Queue verwendet. Deshalb denke ich, dass beide Kanäle ausgegeben werden. 
Es wird das "RAW"-Format verwendet. 4 Bytes pro Sample (2 Bytes pro Kanal).

DIYLAB

(05.09.2020, 09:45)gogosch schrieb: [ -> ]... es gibt für die Teensy Audio Lib einige Beispiele z.B. für "Recording auf SD-Karte". Da wird nur eine recordQueue verwendet.

Ja, das Beispiel ist mir bekannt.
Dort ist die Queue nur an einem Stereokanal des I2S Eingangs angeschlossen.
Ist irgendwie unlogisch, oder?
(04.09.2020, 16:52)DIYLAB schrieb: [ -> ]Keine Ahnung was hier falsch läuft, im Ringpuffer landen nur negative Zahlen  Denker .

Hallo Bruno,

in welchem Datentyp liegen denn die Werte 0 -1 vor, die Du in -1 - 1 umwandeln möchtest?

Vielleicht bringt dich dieser Internetbeitrag weiter:

https://stackoverflow.com/questions/8317...gned-int-c

Gruß
Jürgen
Hallo Bruno,

was mir fehlt, um mich in die Teensy-Programmierung des Projektes einzuarbeiten ist eure konkrete Vorgehensweise, wie sich das Ganze zusammensetzt. Kann ich in einem Thread nachlesen, welche Bibliotheken alle benötigt werden, damit ich einen roten Faden bekomme.

Grüße
Jürgen

gogosch

(05.09.2020, 10:03)DIYLAB schrieb: [ -> ]
(05.09.2020, 09:45)gogosch schrieb: [ -> ]... es gibt für die Teensy Audio Lib einige Beispiele z.B. für "Recording auf SD-Karte". Da wird nur eine recordQueue verwendet.

Ja, das Beispiel ist mir bekannt.
Dort ist die Queue nur an einem Stereokanal des I2S Eingangs angeschlossen.
Ist irgendwie unlogisch, oder?

Ich schau mir das mal morgen an. Bin gerade von einer Radtour heimgekommen und sitze beim Wirten bei einem Bier. Mache morgen eine Aufnahme auf einer SD-Karte und schaue mir das Ergebnis im Hex-Editor an.

DIYLAB

(05.09.2020, 18:34)gogosch schrieb: [ -> ]Ich schau mir das mal morgen an.

Moin,
brauchst Du nicht mehr, ist Mono.
Steht auch in den Kommentaren im Beispielprojekt. Hatte ich überlesen Floet

gogosch

Gerade ausprobiert: Mono!

DIYLAB

(06.09.2020, 08:25)gogosch schrieb: [ -> ]Gerade ausprobiert: Mono!

Jo, schrieb ich doch.

Langsam geht mir das auf den Sack  Lipsrsealed2 .
Wenn ich zum Test zwei Puffer nehme:

Code:
int16_t samplesLeft[256];
int16_t samplesRight[256];

Und die befülle:

Code:
   if (queue1.available() >= 2 && queue2.available() >= 2) {
        memcpy(samplesLeft, queue1.readBuffer(), 256);
        memcpy(samplesRight, queue2.readBuffer(), 256);
        queue1.freeBuffer();
        queue2.freeBuffer();
    }

... landen stat der erwarteten 256 Samples pro Buffer, genau 128 Stück darin.

Code:
    Serial.println("LINKER KANAL:");
        for (int i = 0; i < 256; i++) {
            Serial.print(samplesLeft[i]);
            Serial.print(";");
        }

        Serial.println("RECHTER KANAL:");
        for (int i = 0; i < 256; i++) {
            Serial.print(samplesRight[i]);
            Serial.print(";");
        }

Warum zum Geier?

Code:
LINKER KANAL:
-1378;-1344;-1276;-1128;-960;-844;-898;-1036;-1000;-717;-470;-437;-606;-607;-348;182;639;677;287;-360;-974;-1361;-1577;-1762;-2046;-2339;-2421;-2122;-1449;-687;-183;9;91;184;360;620;791;737;619;632;959;1535;2006;2068;1791;1437;1251;1195;1078;784;438;206;162;233;279;239;154;198;583;1259;1890;2201;2163;1921;1726;1674;1710;1561;1129;422;-251;-687;-881;-909;-978;-1159;-1282;-1256;-1194;-1100;-989;-1030;-1122;-1110;-1011;-757;-326;-56;-35;-101;10;314;571;523;210;-149;-315;-214;-69;-57;-116;-44;217;526;668;517;145;-225;-370;-337;-248;-175;-110;-54;-74;-99;-161;-223;-475;-1201;-2314;-3462;-4191;-4401;-4288;-3996;-3538;-2824;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;
RECHTER KANAL:
-1549;-1560;-1528;-1459;-1529;-1819;-2220;-2447;-2309;-1916;-1461;-1027;-802;-709;-810;-955;-1114;-1278;-1319;-1253;-1269;-1448;-1685;-1843;-1847;-1668;-1448;-1371;-1415;-1485;-1606;-1728;-1615;-1206;-613;70;653;974;1116;1138;1160;1273;1480;1606;1543;1288;949;561;199;64;209;337;271;64;-195;-330;-252;-102;129;456;683;660;448;174;-48;-205;-240;-171;77;401;701;830;737;606;553;549;550;507;334;2;-321;-483;-283;300;954;1395;1620;1599;1380;1054;861;879;1018;1148;1198;952;307;-446;-909;-868;-436;55;248;71;-292;-634;-836;-865;-701;-405;-70;148;114;-105;-376;-480;-381;16;623;1116;1369;1335;1156;1004;1073;1273;1168;584;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;0;

gogosch

Die Angaben beziehen sich immer auf "Bytes" und nicht auf "Samples":
Code:
void continueRecording() {
  if (queue1.available() >= 2) {
    byte buffer[512];
    // Fetch 2 blocks from the audio library and copy
    // into a 512 byte buffer.  The Arduino SD library
    // is most efficient when full 512 byte sector size
    // writes are used.
    memcpy(buffer, queue1.readBuffer(), 256);
    queue1.freeBuffer();
    memcpy(buffer+256, queue1.readBuffer(), 256);
    queue1.freeBuffer();
    // write all 512 bytes to the SD card
    //elapsedMicros usec = 0;
    frec.write(buffer, 512);

DIYLAB

(06.09.2020, 09:37)gogosch schrieb: [ -> ]Die Angaben beziehen sich immer auf "Bytes" und nicht auf "Samples":

Ah, verstehe.
Dann also aus den Bytes die Samples gewinnen.
Bei C# gehts das so:

Code:
for (int i = 0; i < tmpBytes.Length - (bytesPrSample * channels); i += (bytesPrSample * channels)) {
                    switch (bitsPrSample) {
                        case 16:
                            bit16 = BitConverter.ToInt16(tmpBytes, i);
                            loopSamplesL.Add(bit16);
                            if (channels >= 2) {
                                bit16 = BitConverter.ToInt16(tmpBytes, i + bytesPrSample);
                                loopSamplesR.Add(bit16);
                            }
                            break;
                        case 32:
                            bit32 = BitConverter.ToSingle(tmpBytes, i);
                            loopSamplesL.Add((short)(bit32 * Int16.MaxValue));
                            if (channels >= 2) {
                                bit32 = BitConverter.ToSingle(tmpBytes, i + bytesPrSample);
                                loopSamplesR.Add((short)(bit32 * Int16.MaxValue));
                            }
                            break;
                    }
                }

Bei C++ bin ich raus, keine Ahnung Pardon

DIYLAB

Moin,

die Korrelationsanzeige am Teesy geht jetzt perfekt und sieht exakt so aus wie bei der Desktopversion.
Nächster Schritt ist das Goniometer für den Teensy.
Da ist die Nuss "Bezierkurven" zu knacken.

Viele Grüße
Bruno

PS: Dauert zur Zeit alles noch länger als vorher. Bin beruflich mit der Entwicklung von CO2 Messstationen beschäftigt, die Ihre Daten via WLAN direkt in eine DB pumpen und mittels Grafana wird visualisiert - spannendes Thema Thumbsup .

DIYLAB

Moin,

jetzt sind wir so weit und hängen an den Bezierkurven fest  Denker .
Ich kann die C# Methode, die ich in der Desktopversion benutze, einfach nicht nach Arduino/C++ umsetzen.
Das übersteigt meinen mathematischen Horizont und meine C++ Kenntnisse.

In der Desktopversion benutze ich dies hier: https://docs.microsoft.com/de-de/dotnet/...work-4.7.2
Es wird einfach ein Array aus Points übergeben und zack -> Kurve.

Ich finde einfach keine Arduino Libs zum Zeichnen dieser Kurven.

Alles Scheize,
Deine Elli
Hi Bruno

nur mut und gedult, du schafft das schon  Thumbsup Thumbsup

gogosch

Code:
double x = queueBufferleft[i];  // Left  channel is mapped to x axis
double y = queueBufferRight[i]; // Right channel is mapped to y axis

double radius = sqrt((x * x) + (y * y));
double angle = atan(y/x);

if ((x < 0 && y > 0) || (x < 0 && y < 0)) {
  angle += 3.14159265; // Pi radians = 180 degrees
}
else if (x > 0 && y < 0) {
  angle += 6.28318530; // 2Pi radians = 360 degrees
}

if (x == 0) {
  angle = y > 0 ? 1.57079633 : 4.71238898; // 90 or 270 degrees
}
else if (y == 0) {
  angle = x > 0 ? 0 : 3.14159265; // 0 or 180 degrees
}

// Rotate coordinate by 45 degrees counter clockwise
angle += 0.78539816;
          
// Convert polar coordinate back to cartesian coordinate.
double xRotated = radius * cos(angle);
double yRotated = radius * sin(angle);
Versuch macht kluch ..... Floet Natürlich müssen die errechneten Koordinaten noch "normalisiert" d. h. auf das Ausgabemedium skaliert werden. Pro Samplepaar wird ein Punkt errechnet.
Hallo Bruno,

könnte das weiterhelfen:

https://github.com/StuffAndyMakes/arduino-bezier

Gruß
Jürgen

DIYLAB

(10.09.2020, 19:04)bornemju schrieb: [ -> ]könnte das weiterhelfen:
https://github.com/StuffAndyMakes/arduino-bezier

Ja Jürgen, kenne ich schon, trotzdem danke.
Du müsstest doch eigentlich zu dem Goniometer-Testcode und dem Gogosch-Code etwas sagen können, was man auch als Nichtfachmann verstehen kann?
Das Hauptproblem ist momentan nicht das (schnelle!!!) Zeichnen der Kurven (das Beste kommt zum Schluss), sondern die von der Audiolib bereitgestellten Audiosamples.
Die Gewinnung Dieser ist leider im Vergleich zum PC und den Desktop-Testmodulen unterirdisch schlecht.
Vor allem feuert das Ding pausenlos irgendwelche Querschläger in die Queue, wo eigentlich Ruhe sein sollte  Denker
Die Gogosch Implementierung (wo auch immer die so schnell herkam) schaue ich mir Morgen mal an, danke dafür.
So ein bisschen Erklärung dazu für alle Leser wäre sicher schön gewesen, aber was nicht ist, das ist halt nicht.
Falls ich überhaupt das Codefragment zum laufen bekomme, hoffe ich sehr, dass sich dann die Kurven (momentan sind es Punkte), so verhalten wie in der Desktopversion.
Kann ich mir aber nicht vorstellen, dafür sind die Audiosamples am Teensy einfach zu schlecht und ich weiß nicht warum.

AtGogosch
Noch ein paar Anmerkungen zu Deinem Code, der Queue und den Samples:

Code:
double x = queueBufferleft[i];  // Left  channel is mapped to x axis
double y = queueBufferRight[i]; // Right channel is mapped to y axis

Das verwirrt mich nun erst mal richtig  Denker
Was genau erwartet denn der Code aus den Puffern?
Schon aufbereitete DOUBLE, oder doch BYTES oder eher SHORTS?

Nehmen wir mal einen Block der Queue, der hat 128 Bytes.
Sauge ich mir die 128 Bytes ab, kommen auch 128 Bytes in den Puffer, ok,
Daraus gewinnen wir durch das Shiften Samples in SHORT, also genau die Hälfte, da ein SHORT aus zwei Bytes besteht.
So mache ich das, wie Du ja im mini Testcode sehen kannst.
Nur das ich 2Kb aus der Queue sauge. Das kostet eklig viel Zeit, da er ja wartet, bis 16 Blöcke a 128 Bytes neu in der Queue angekommen sind.

Nachdem Du mir ja den Tipp gabst, den Puffer in Bytes zu benutzen und daraus dann die Shorts zu generieren, hielt ich mich daran und es geht ja auch.
Interessanter Weise steht in der Beschreibung der Record-Queue (von Bytes keine Rede):
"Read a single audio packet. A pointer to a 128 sample array of 16 bit integers is returned. NULL is returned if no packets are available."
Aha, toll!
Macht man nun ein Array als 16 Bit Integer, also SHORT, und füllt es mit dem oben erwähnten "single audio packet", kommen aber nur 64 Shorts in den Puffer.
Kann ich auch verstehen, aber warum zum Geier steht dort explizit: A pointer to a 128 sample array of 16 bit integers is returned.
Was soll das? Fehler? Wahrscheinlich bin ich nur zu blöd.

Und nun kommst Du zur Krönung mit DOUBLE daher  Dance3 .
Also was genau soll denn da nun rein?
Oder denke ich falsch? Kann man bei C++ seine Datentypen wechseln wie Unterhosen?
Ich dachte, nur PHP vergleicht Äpfel mit Birnen LOL
Vielleicht nur eine Namensgleichheit der Puffer bei Deinem Code und meinem?
Vielleicht stopfst Du da auch etwas rein, was nicht dokumentiert ist - ich weiß es einfach nicht.

Gute N8

PS: Das schönste an dieser Woche ist mein neues Auto, das macht alles ohne das ich raten muss  Thumbsup  Hiermit gebe ich allen Lesern ein Auto-Eis aus! Lasst es euch schmecken und kleckert nicht  Floet
Hallo Bruno und Gogosch,

Double ist mir schon klar, da die Werte quadriert werden. Sonst läuft man in die Gefahr "Out of Range".

Meiner Meinung nach fehlt hier aber auch ein Quadrant:...

else if (x > 0 && y < 0) Gogosch's Version

müsste hier nicht stehen...

else if ((x > 0 && y > 0) || (x > 0 && y < 0)) Meine Version

Gute N00001000 zusammen.
Jürgen