Moinmoin,
ich wollt ein wenig mit dem Audiocodec auf dem STM32F746-Discoboard
rumspielen. Ich hab per Cube alles soweit eingestellt, dass er die
Samples mit 96kHz und 16bit sehen möchte.
Meine Überlegung war: "Bei 96kHz sollten 96000 16bit-Werte eine Sekunde
Krach ergeben." Also ein Array uint16_t Soundpuffer[96000] erstellt.
Dann dachte ich mir, dass ich den Krach gern mit 100Hz hätte. Also
96000/100 macht 960 Samples nach dem sich was wiederholen sollte. Bei
16bit hab ich 2^16 Werte, geteilt durch die 960 Samples macht etwa 68.
Also in einer Schleife 68 aufaddieren sollte dank Überlauf ein Sägezahn
ergeben.
1
i=0;
2
Filler=0;
3
while(i<96000)
4
{
5
Audiopuffer[i]=Filler;
6
Filler+=68;//2^16/960 = 68. ergibt einen Anstieg von 0 auf max in einer 100stel Sekunde bei 96kHz Samplefrequenz
Klingt zwar irgendwie sägezahnig, ist aber gefühlt eher nur ne 10tel
Sekunde lang, dafür könnte es aber rund 1kHz sein... Mein Gehör ist weit
davon entfernt, ein Absolutes zu sein ;-).
Fällt da spontan jemandem von euch ein, wo mein Denkfehler liegt?
Size soll in Bytes und nicht Samples angegeben werden. Die Anmerkung "In
memory, first element is for left channel, second element is for right
channel" verstehe ich noch nicht ganz. Soll das bedeuten, dass die
geraden Array Eintrage fuer den linken und ungeraden fuer den rechten
Kanal sind? Dann haette dein Buffer schonmal nur Content fuer 500 ms und
mit dem fehlenden Faktor 2 nur noch 250 ms.
Aber ohne Gewaehr, nur mal so ein Schnellschuss nach kurzer Google
Recherche.
Danke dir, das klingt nach nem handfesten Ansatzpunkt. Ich werd mich
zurückmelden, ob es daran lag/geklappt hat oder auch nicht.
Tobias B. schrieb:> Size soll in Bytes und nicht Samples angegeben werden. Die Anmerkung "In> memory, first element is for left channel, second element is for right> channel" verstehe ich noch nicht ganz. Soll das bedeuten, dass die> geraden Array Eintrage fuer den linken und ungeraden fuer den rechten> Kanal sind? Dann haette dein Buffer schonmal nur Content fuer 500 ms und> mit dem fehlenden Faktor 2 nur noch 250 ms.
Ich ging davon aus, dass sizeof die Größe des Arrays in Elementen
ausgibt, hatte das mal anhand eines 8bit-Arrays "verifiziert" :D
Und das mit dem rechten und linken Channel klingt auch sehr gut, ich
hatte mich schon gefragt, wie man dem rechten und linken Kanal zuweist,
da es aus beiden Kopfhörern piepte.
J. T. schrieb:> Ich ging davon aus, dass sizeof die Größe des Arrays in Elementen> ausgibt, hatte das mal anhand eines 8bit-Arrays "verifiziert" :D
Da hast du allerdings recht, das hab ich verratzt. Das sollte daher
korrekt sein. :-)
Hast du ein Oszi mit dem du mal am Audio Ausgang nachmessen kannst?
Du kannst auch mal versuchen jedne zweiten Wert auf 0 zu setzen, wenn
dann ein Kanal still ist, dann hast du da schonmal Gewissheit.
P.S.
"Der" sagt:
Size: Number of audio data in BYTES unit.
* In memory, first element is for left channel, second element
is for right channel.
sizeof sagt mir 192000, also gibt es die Größe doch schon in Bytes aus?
Und wenn ich den Audiopuffer so initialisiere:
1
i=0;
2
while(i<96000)
3
{
4
Audiopuffer[i]=Filler;
5
Filler+=68;//2^16/960 = 68. ergibt einen Anstieg von 0 auf max in einer 100stel Sekunde bei 96kHz Samplefrequenz
Tobias B. schrieb:> Du kannst auch mal versuchen jedne zweiten Wert auf 0 zu setzen, wenn> dann ein Kanal still ist, dann hast du da schonmal Gewissheit.
Der Gedanke kam mir in der Zwischenzeit auch schon :D, aber wie gesagt,
trotzdem Ton auf beiden Ohren....
Tobias B. schrieb:> Hast du ein Oszi mit dem du mal am Audio Ausgang nachmessen kannst?
Das allerdings ist eine Idee, auf die hät ich selbst auch schonmal
kommen können. Es steht hier direkt neben mir :D
Irgendwie ist auf dem Kopfhörerausgang gar nichts zu messen, egal ob ich
Kopfhörer drin hab oder nicht.... Am Speaker-Ausgang hab ich dagegen ein
Rechteck mit ca680kHz und etwa 3Vpp
Tobias B. schrieb:> i = 0;> while(i < 96000)> {> Audiopuffer[i] = Filler;> Filler += 68; //2^16/960 = 68. ergibt einen Anstieg von 0 auf max> in einer 100stel Sekunde bei 96kHz Samplefrequenz> i++;> Audiopuffer[i] = 0;> i++;> }
Auch so bleibt der Ton auf beiden Ohren....
Vermutlich brauch ich auch irgendwelche Wartezeiten bzw irgendeine Art
von Timing. Ich hab jetzt mal 2 unterschiedliche Töne eingerichtet, der
eine soll vor der mainwhile(1)loop kommen, der andere dann in der
while(1). Wenn ich Singlesteppe, hört man auch die Unterschiedlichen
Töne, wenn ich es normal laufen lasse, kommt der 2Ton 2-3mal und dann
gar nichts mehr(Der erste Ton wird dann "übersprungen"). Ich hatte
irgendwann mal eine Frequenz erwischt, da kam dann ein Dauerton.... Aber
jetzt kommt nur dööd dööd dööd oder dööd dööd :D
Hier ist ein Beispiel, bei dem das jemand zum Laufen bekommen hat:
http://www.openstm32.org/forumthread897
Siehe zweiter Post. Magst du mal versuchen ob du das kopiert und
lauffaehig bekommst?
Ich habe leider das Board nicht zum selbst testen. :-(
Tobias B. schrieb:> Siehe zweiter Post. Magst du mal versuchen ob du das kopiert und> lauffaehig bekommst?
Kann ich mal machen.
Mal ne Frage nebenbei, du nennst dich ttobsen. Du bist nich zufällig DER
TobiTobsen? :D
So ich hab das mal so weit umgesetzt. Er spielt beim Sinus nichts
hörbares. Da bei dem Beispiel mit 8kHz Samplefrequenz gespielt wird,
kommen "meine" Töne (hab das einfach schnell in meinem Project
integriert, dass is immer so aufwändig ein neues zu erstellen) natürlich
nun viel zu tief.
Was aber scheinbar sehr hilfreich ist, ist der TransferComplete
Interrupt, bzw den Codec anzuhalten.
J. T. schrieb:> Mal ne Frage nebenbei, du nennst dich ttobsen. Du bist nich zufällig DER> TobiTobsen? :D
Also ich kenne nur den 5 Sterne Deluxe Tobi Tobsen, der bin ich nicht.
Aber ein Kumpel hat mich frueher (bestimmt schon 20 Jahre her) wegen dem
echten Tobi Tobsen immer so genannt und weil die ganzen TobiTobsen Login
Namen immer vergeben waren, habe ich halt ttobsen genommen. Kann man
sich gut merken. :-D
J. T. schrieb:> So ich hab das mal so weit umgesetzt. Er spielt beim Sinus nichts> hörbares. Da bei dem Beispiel mit 8kHz Samplefrequenz gespielt wird,> kommen "meine" Töne (hab das einfach schnell in meinem Project> integriert, dass is immer so aufwändig ein neues zu erstellen) natürlich> nun viel zu tief.>> Was aber scheinbar sehr hilfreich ist, ist der TransferComplete> Interrupt, bzw den Codec anzuhalten.
Ok, dann muss ich leider auch erstmal passen. Da ich das Board nicht
habe, faellt es mir ziemlich schwer da remote zu helfen. Gibt es keine
passenden Examples zum Board die Out-of-the-Box lauffaehig sind?
Tobias B. schrieb:> Also ich kenne nur den 5 Sterne Deluxe Tobi Tobsen,
Auf den hab ich angespielt ;-)
Tobias B. schrieb:> Ok, dann muss ich leider auch erstmal passen. Da ich das Board nicht> habe, faellt es mir ziemlich schwer da remote zu helfen. Gibt es keine> passenden Examples zum Board die Out-of-the-Box lauffaehig sind?
Ich steig da irgendwie noch nicht so ganz durch. Angeblich sollen alle
Beispiele Problemlos out of the Box laufen. Darunter verstehe ich
"öffnen, compile drücken, läuft". Das ging irgendwie noch bei keinem der
Beispiele. Desweiteren hab ich so meine Probleme, der Struktur der
Beispiele zu folgen.
Bei dem Audiorecorderbeispiel war zb das Problem (davon ab das erst mal
soweit umzugestalten dass es sich überhaupt kompilieren ließ), dass das
Board keine meiner sd-Karten erkannt hat, aber für das Beispiel gern
eine hätte.
So langsam klappt es ein wenig mehr. Ich hatte nur mit 30 von 100
Lautstärke initialisiert. Ich bin jetzt mal auf 90 hochgegangen, und
plötzlich kommt da richtig was raus. Ich hab mir ne Sinustabelle mit
9600 Stellen erstellt.
uint16_t Audiopuffer[9600*2] = {0};
i = 0;
while(i < 9600)
{
Audiopuffer[ (i*2) ] = Sinustabelle[i];
Audiopuffer[ ( (i*2) + 1 ) ] = 0;
i++;
}
^^so schmeiß ich die in Puffer.
BSP_AUDIO_OUT_Play(&Audiopuffer[0], sizeof(Audiopuffer) );
HAL_Delay(10);
BSP_AUDIO_OUT_Stop(CODEC_PDWN_SW);
so spiel ichs ab.
Aber es kommt nur ca ne viertel Periode vom Sinus raus. Ich kann nachher
mal schaun ob ich Oszibilder hochgeladen bekomm, hab grad kein USB stick
zur Hand.
Es kommt aber immerhin schonmal nur auf einem Kanal raus.
Ok, wenn ich das Delay auf 40ms stelle, kommen ein verquerer Sinus raus.
Eine "nach unten offene Parabel", dann springts hoch, es kommt eine nach
oben offene Parabel, und dann der Rest der 40ms Pause.
Die Sinustabelle hab ich hiermit erstellt:
https://daycounter.com/Calculators/Sine-Generator-Calculator2.phtml
Und wenn ich den Audiopuffer als int16_t deklariere, ändert sich nix...
Hallo, ich weiß nicht, ob das hier weiter hilft, aber schau dir doch mal
eine "WAV-Datei" an. Da brauchts einen Header, in dem alle Daten wie
Sample-Rate, wieviele Kanäle usw. eingetragen sind. Das wird bei anderen
Codecs ähnlich sein. Eine WAV kannst du z.B. mit Audacity erzeugen.
Gruß Rainer
Rainer V. schrieb:> Hallo, ich weiß nicht, ob das hier weiter hilft, aber schau dir doch mal> eine "WAV-Datei" an. Da brauchts einen Header, in dem alle Daten wie> Sample-Rate, wieviele Kanäle usw. eingetragen sind. Das wird bei anderen> Codecs ähnlich sein. Eine WAV kannst du z.B. mit Audacity erzeugen.> Gruß Rainer
Vom Prinzip her ne gute Idee. Mein Plan ist langfristig eher der
"umgekehrte" Weg. Ich "male" ne Wellenform aufs Display und die soll
dann abgespielt werden. Quasi n handgestrickter einfacher
Arbiträrgenerator.
J. T. schrieb:> Vom Prinzip her ne gute Idee. Mein Plan ist langfristig eher der> "umgekehrte" Weg
Ja, kann ich verstehen, aber deine Kurve muß als Amplitudenwerte an das
"Abspielgerät" gesendet werden und das will möglicherweise sowas wie
eine WAV-Datei sehen. Es ist da wohl egal, wie du beginnst!
Viel Erfolg und Gruß, Rainer
Rainer V. schrieb:> Ja, kann ich verstehen, aber deine Kurve muß als Amplitudenwerte an das> "Abspielgerät" gesendet werden und das will möglicherweise sowas wie> eine WAV-Datei sehen.
So wie ich das verstanden hab, will es die Amplitudenwerte einfach als
nackte 16bit Zahlen haben. Und wenn man von der "Verknotung" vom Sinus
absieht, klappt es ja schonmal ganz grob und halbwegs. Das wird
vermutlich irgendwo am Vorzeichen klemmen. Ich hatte diese Wellenform
schonmal als ich sowas in wesentlich primitiver mit nem AVR in 8bit
gebastelt hab. Vermutlich schlummert da auch die Lösung drin, ich finds
nur nicht mehr in den tiefen der Festplatten.
Danke dir.
Ich hab nun einfach mal einen 2^16 großen Audiopuffer von 0-65535
initialisiert, siehe Bildchen. links, mit der "länger abgeschnittenen
Spitze" mit Kopfhörer, rechts ohne Kopfhörer. So pi mal Auge, irgendwie
sind alle meine USBsticks auf Wanderschaft.... Belastet etwa 2Vpp
unbelastet etwa 3Vpp.
Das sieht doch nach Clipping plus 2er Komplement aus?
So ich hab mal ein wenig weiterprobieren können. Ich hab inzwischen die
Zuordnung der Kanäle zum "Audiopuffer" verstanden. So halbwegs zumindest
:D
BSP_AUDIO_OUT_SetAudioFrameSlot(CODEC_AUDIOFRAME_SLOT_02);
schaltet den Kopfhörerausgang frei, SLOT_13 wäre Speaker, und SLOT_0123
wäre beides.
Audiopuffer[SLOT_0] entspricht somit Kopfhörer links
Audiopuffer[SLOT_1] " " Speaker "
Audiopuffer[SLOT_2] " " Kopfhörer rechts
Audiopuffer[SLOT_3] " " Speaker "
und das erwartet er immer so, auch wenn man nur die Kopfhörer aktiviert.
Sprich wenn ich nur die Kopfhörer aktiviere, muss ich jeden 2ten Platz
im Array überspringen, damit es rechts und links raustönt. Das wundert
mich aus Speicherplatzgründen ein wenig, ist aber nicht das eigentlich
Problem, das ich jetzt habe.
Ich hab mir nun eine neue Sinustabelle erstellt, über eine volle
Schwingung (ich weiß, ein viertel würde langen, aber zur Zeit hab ich
noch genug Speicher) mit 48000 Stützstellen. Dann der Audiopuffer[9600],
sprich 2400 Words pro Slot.
1
intmain(void)
2
{
3
/* USER CODE BEGIN 1 */
4
5
uint32_ti=0;
6
uint32_tk=0;
7
8
uint16_tAudiopuffer[9600]={0};
9
uint16_tSprungweite=10;
10
externuint16_tsinus[];
11
12
while(1)
13
{
14
i=0;
15
while(i<(sizeof(Audiopuffer)/8))// /8 wegen 4Slots und dann noch durch 2 wegen 16bit
16
{
17
i++;//verschiebt in der Tabelle um 1/4 und Modulo damit er in der Tabelle bleibt
Die 90° Phasenverschiebung sehe ich. Es sieht im großen und ganzen auch
Sinusähnlich aus. (Siehe Bild, nur abfotografiert, meine USB-Sticks
spielen immer noch alle verstecken mit mir.) Wären diese Sprünge nicht,
wäre das ein fast schöner Sinus. Irgendwo bricht er wohl auch
zwischendurch auf Null ein. Mir ist jetzt nicht ganz klar wo diese
Sprünge herkommen. k ändert sich ausserhalb der Schleife nicht. Also
sollte die Stelle, die er beim nächsten Durchlauf als erstes aus der
Sinustabelle ausliest, die letzte Stelle des vorherigen Durchlaufes plus
ein sein, oder nicht? Aber so wie es aussieht, springt er halt doch
irgendwie.
Wenn ich das ganze durchsteppe, funktioniert die Ausgabe leider nicht,
aber k verhält sich so wie ich mir das gedacht, und in der Frage
beschrieben hab. Auch die Wert im Audiopuffer sind soweit plausibel. Der
letzte Slot geht schlüssig mit dem ersten Slot vom nächsten Durchlauf
weiter...
Ich hab während des Schreibens nochmal ein HAL_Delay(10) ans Ende (nach
BSP_AUDIO_OUT_Play) gesetzt. Das zeigt, dass der Sprung gar nicht beim
erneuten Play auftritt, sondern mitten in der Mitte. (Siehe 2tes Bild,
hier 20ms pro Diverse, beim ersten waren es 10ms/Div). Wenn ich das k
modulo (sizeof(sinus)/4) nehme, kommt nur der halbe Sinus raus, und wenn
ich modulo (sizeof(sinus) nehme, kommt eine Hälfte der Ausgabe eine
ganze Schwingung und nochmal solange "Rauschen", naja hinter dem Sinus
werden auch noch andere Daten liegen :D.
Das war nun wieder etwas länger, aber wenn mir jemand sagen könnte,
welchen Denkfehler ich mit dem k mache, wäre mir das durchaus sehr recht
;-)
MfG Chaos
Hier nochmal das Bild2 in richtig ausgeschnitten :D
P.S.
Das Delay ist auch irgendwie deutlich kürzer als 10ms, hab aber auch in
Cube nicht drauf geachtet, wie der Timer delaymäßig eingerichtet ist.
Ich hab mit nem komplett geleerten Projekt angefangen und nach und nach
zugeklickt, was ihm gefehlt hat.
J. T. schrieb:> So wie ich das verstanden hab, will es die Amplitudenwerte> einfach als nackte 16bit Zahlen haben.
Signed oder Unsigned? Und werden auch tatsächlich alle 16 Bit benutzt,
oder eventuell weniger?
S. R. schrieb:> Signed oder Unsigned? Und werden auch tatsächlich alle 16 Bit benutzt,> oder eventuell weniger?
Ich vermute, das wird irgendwas 2er Komplementiges sein. Meine Sinus
Tabelle liegt als unsigned 16bit vor, und die Werte gehen von 0-2^16.
Auch die BSP-Audio Funktionen erwarten unsigned.
Allerdings gab es anfänglich immer einen Sprung um die Mitte. Wenn ich
von den Werten 2^15 abziehe, passte es aber, undes kam ein Sinus raus.
Jetzt ist aber das Problem, das meine Sinustbelle länger als der
Audiopuffwr ist, und es zu den in den Bildern gezeigtwn Sprüngen kommt.
P.S. vom Handy geschrieben, wer Tipfehler findet, darf sie behalten.
J. T. schrieb:> Dann dachte ich mir, dass ich den Krach gern mit 100Hz hätte. Also> 96000/100 macht 960 Samples
Ohweh! Dann musst du auch mit 1/100 der Frequenz abspielen.
Audiomann schrieb:> Ohweh! Dann musst du auch mit 1/100 der Frequenz abspielen.
Das musst du mir erklären. Ich habe eine langsame Schwingung. (ich
vermute du beziehst dich ziemlich auf den Anfang) Eine Schwingung über
96000 Samples. Das entspräche 1Hz. Nun wollte ich an der Stelle 100Hz
haben. Du meinst also, wenn ich meine Samples mit 1/100 der Frequenz,
sprich 100mal LANGSAMER abspiele, wird es im großen ganzen schneller???
Davon ab, dass die ganzen Berechnungen von da oben hinfällig sind, da
ich von falschen Voraussetzungen ausging.
Aber auf die Erklärung wär ich trotzdem gespannt.