amiga-news ENGLISH VERSION
.
Links| Forum| Kommentare| News melden
.
Chat| Umfragen| Newsticker| Archiv
.

amiga-news.de Forum > Programmierung > Tonerkennung [ - Suche - Neue Beiträge - Registrieren - Login - ]

Erste 1 2 3 4 5 -6- 7 8 9 10 11 [ - Beitrag schreiben - ]

09.09.2006, 10:19 Uhr

MaikG
Posts: 5172
Nutzer
>Das ist schon recht merkwürdig. Den Goertzel hast Du auch
>rausgenommen und die Werte in ein Array schreiben lassen?

Ja.

>Wenn ja, und die Timer sind auch raus, verbockt MB da irgendwas.

Im moment ist nur der Timer drin, nehme ich den noch raus habe
ich nur eine schleife die die "sekunden zählt" und die ist ganz
schnell fertig.


>Allein das ist schon merkwürdig. Die Textausgaben kosten eine Menge
>Zeit, da sollte sich ein Weglassen schon bemerkbar machen.

1x Pro Sekunde die Zeit über Intuition ausgeben kostet nicht
viel Zeit. Dann würde das Programm ja auch querschlagen wenn ich
Clock auf der WB hätte...


>Einen Request mit TR_GETSYSTIME schicken, das Ergebnis + 125 micros
>in den IOrequest eintragen, weg damit zum timer.device, warten.

Okay, das muss ich mal probieren.

[ - Antworten - Zitieren - Direktlink - ]

09.09.2006, 13:21 Uhr

whose
Posts: 2156
Nutzer
Zitat:
Original von MaikG:
>Allein das ist schon merkwürdig. Die Textausgaben kosten eine Menge
>Zeit, da sollte sich ein Weglassen schon bemerkbar machen.

1x Pro Sekunde die Zeit über Intuition ausgeben kostet nicht
viel Zeit. Dann würde das Programm ja auch querschlagen wenn ich
Clock auf der WB hätte...


Ich bin davon ausgegangen, daß MB daraus ein CLI-Programm generiert. Textausgaben in den CLI kosten schon recht viel Zeit. Intuition ist da ja nur die letzte Instanz, da kommt ja noch der CON-Handler dazwischen, dos.library, diverser Format-Code der Textausgabefunktion etc. Laß doch mal 100 Mal in einer Schleife einen Text ausgeben, das dauert dann schon ne ganze Weile.

Ja, bei z.B. LimpidClock schlägt es auch quer, und zwar gewaltig. Sehr schön zu sehen, wenn man Thilos AsteroidsTR dazu laufen läßt. Jede Sekunde ruckelts einmal kurz. WB-Uhren (Uhren generell) sollte man bei solchen Tests beenden. Das hat aber weniger mit den Timern zu tun als mit Bitmap-Locks u.Ä.

Zitat:
>Einen Request mit TR_GETSYSTIME schicken, das Ergebnis + 125 micros
>in den IOrequest eintragen, weg damit zum timer.device, warten.

Okay, das muss ich mal probieren.


Nicht vergessen, aus TR_GETSYSTIME dann TR_ADDREQUEST zu machen. Oder, noch besser, mit zwei IORequests arbeiten.

Grüße

--
---

:boing: µA1 PPC 750GX-800
:boing: A4000 PPC 604e-233

[ - Antworten - Zitieren - Direktlink - ]

09.09.2006, 15:20 Uhr

MaikG
Posts: 5172
Nutzer
Ich bin davon ausgegangen, daß MB daraus ein CLI-Programm generiert.

Nein, das macht nur C, MB hat ein eigenes Fenster wo man dann
drauf Printen kann etc. ist aber lahm auf CGX.


>Nicht vergessen, aus TR_GETSYSTIME dann TR_ADDREQUEST zu machen.
>Oder, noch besser, mit zwei IORequests arbeiten.

Geht nicht wartet nur ewig:

code:
WHILE myseconds%<20
        POKEW tr& + tr_node% + IORequestio_Command%, TR_GETSYSTIME&
        junk& = DoIO&(tr&)

        mymicros&=PEEKL(tr& + tr_time% + tv_micro%)
        POKEW tr& + tr_node% + IORequestio_Command%, TR_ADDREQUEST&
        POKEL tr& + tr_time% + tv_micro%, mymicros&+125& REM 125=8000Hz

        SendIO&(tr&)
        INCR mycount%:IF mycount%=8000 THEN mycount%=0:INCR myseconds% rem :move rpS&,20,25:Text rpS&, SADD(TIME$+CHR$(0)),8
        REM bla%=goertzel%((PEEKB(&hBFE101) - 127)<<8)
        junk& = WaitIO&(tr&) REM junk% = finish_wait(tr&)
      WEND


[ - Antworten - Zitieren - Direktlink - ]

09.09.2006, 19:50 Uhr

Mad_Dog
Posts: 1944
Nutzer
So. Ich hab das "Monoscope" nochmal etwas überarbeitet (u.a. Code aufgeräumt).
Das Archiv mit dem Sourcecode und dem Executable (68000) gibt's hier:
http://www.norman-interactive.com/files/Monoscope.lha

Wer irgendeinen Parallelportsampler hat, kanns testen. Ich würde mich drüber freuen zu hören, mit welchen Samplern das so funktioniert.

Das Zeichnen der Linien ist leider Megalahm. Das sieht nur auf ner Grafikkarte einigermaßen gut aus. Auf AGA ist's ein Krampf. :(
Dazu gleich mehr...

Aber das Timing scheint einigermaßen zu passen (o.k. hab's nicht nachgemessen). Und ja: In dem alten Code hab ich mehrfach auf das timer.device gewartet, was natürlich Quatsch ist. WaitIO() müsste völlig reichen.
--
http://www.norman-interactive.com

[ - Antworten - Zitieren - Direktlink - ]

09.09.2006, 20:00 Uhr

Mad_Dog
Posts: 1944
Nutzer
Für MaikG hier nochmal meine neue Funktion zum Auslesen des Samples (für ein Zeitfenster):
c code:
// Ein Zeitfenster lesen.
void ReadFrame(struct Scope *sc)
{
   unsigned int t;

   /*  Hier werden die Werte gesammelt
    */
   for (t=0;t<sc->Size;t++)
   {
      sc->TimerIO->tr_node.io_Command = TR_ADDREQUEST;
      sc->TimerIO->tr_time.tv_secs = 0;
      sc->TimerIO->tr_time.tv_micro = sc->Range;

      SendIO((struct IORequest *)sc->TimerIO);
      WaitIO((struct IORequest *)sc->TimerIO);

      // Wert vom Parallelport kopieren
      READ_PAR(sc->Data[t]);
   }
}


Die verschiedenen Variablen des Oszis hab ich zu einer Struktur zusammengefasst,
damit nicht soviele globale Variablen und undurchschaubare Makros rumgammeln:
c code:
// Strukturtyp für das Osziloskop
struct Scope
{
   ULONG SamplingFreq; // Die Samplingfrequenz in Herz
   double Time;        // Das Zeitfenster in Sekunden
   int   Range;        // Die Periode in Mikrosekunden
   UBYTE *Data;        // Die Daten für das Sample
   ULONG Size;         // Größe des Puffers in Byte   
   LONG  Pen;          // Pennummer der Farbe zum Zeichnen
   LONG  Background;   // Pennummer für Hintergrund
   struct MsgPort *TimerMP;
   struct timerequest *TimerIO;
};


Und so wird eine solche Struktur angelegt:
c code:
/*  Scope
 *
 *  Osziloskop erzeugen:
 *
 *  Eingabeparameter: ULONG f  - Die Samplingfrequenz
 *                    double t - Dauer des Samples in Sekunden
 *                    LONG p   - Pen Nummer zum Zeichnen
 *                    LONG b   - Pen Nummer für Hintergrund
 *  Rückgabe:         struct Scope* - Zeiger auf Scope Struktur
 *
 */
struct Scope *CreateScope(ULONG f,double t,LONG p, LONG b)
{
   struct Scope *sc;

   sc = (struct Scope *) malloc(sizeof(struct Scope));

   sc->SamplingFreq = f;
   sc->Time = t;
   sc->Range = (int)1E6/f;
   sc->Size = (ULONG)(f*t);
   sc->Data = (UBYTE *)malloc(sc->Size);
   sc->Pen = p;
   sc->Background = b;
   sc->TimerMP = CreateMsgPort();
   sc->TimerIO = (struct timerequest *) CreateIORequest(sc->TimerMP,sizeof(struct timerequest));

   return sc; 
}

--
http://www.norman-interactive.com

[ - Antworten - Zitieren - Direktlink - ]

09.09.2006, 20:07 Uhr

Mad_Dog
Posts: 1944
Nutzer
Und auch wenn es jetzt ein wenig offtopic ist:
Wie gesagt, mit AGA ist das Zeichnen der Linien mega-lahm, auf meiner CV64/3D unter CGX geht's ganz gut.

Die Funktion zum Zeichnen des Oszis sieht so aus:
c code:
/*  DrawScope
 *
 *  Zeichnet das Osziloskop in ein Fenster
 *
 *  Eingabe: struct Window *Win - Zeiger das Fenster, in das gezeichnet werden soll
 *           struct Scope  *sc  - Zeiger auf Osziloskop Struktur
 */
void DrawScope(struct Window *Win,struct Scope *sc)
{
   register int t;
   register struct RastPort *rp;     // RastPort des Fensters
   register ULONG zero;

   rp = Win->RPort;

   zero = Win->GZZHeight/2;

   SetRast(rp,sc->Background);
   SetAPen(rp,sc->Pen);

   for (t=0;t<sc->Size;t++)
   {
      Move(rp,t,zero);
      Draw(rp,t,sc->Data[t]);
   }
}


Da es - wie gesagt - auf AGA grausam ist, habe ich eine alternative Funktion geschrieben, die zuerst in einen temporären RastPort zeichnet und dann auf den RastPort des Fensters blittet (diese Funktion ist im Programm nicht aktiv):
c code:
void DrawScopeBlitter(struct Window *Win,struct RastPort *trp,struct Scope *sc)
{
   register int t;
   register struct RastPort *rp;     // RastPort des Fensters
   ULONG width,height;
   register ULONG zero;

   rp = Win->RPort;

   width = Win->GZZWidth;
   height = Win->GZZHeight;

   zero = Win->GZZHeight/2;

   SetRast(trp,sc->Background);
   SetAPen(trp,sc->Pen);

   for (t=0;t<sc->Size;t++)
   {
      Move(trp,t,zero);
      Draw(trp,t,sc->Data[t]);
   }

    ClipBlit(trp,0,0,rp,0,0,width,height,0xC0);
    WaitBlit();

}


Das verhindert zwar das Flackern auf AGA, ist aber dafür selbst unter CGX noch langsamer als die andere Funktion.

Deshalb meine Frage: Wie kann man das beschleunigen? Ist ein systemkonformes DoubleBuffering auch für einzelne Fenster möglich?

--
http://www.norman-interactive.com

[ - Antworten - Zitieren - Direktlink - ]

09.09.2006, 20:59 Uhr

DaxB
Posts: 1421
Nutzer
@Mad_Dog:
Monoscope funzt hier mit TechnoSoundTurbo2 Sampler. Allerdings scheint die Darstellung nicht richtig zu sein. Es wird nur selten etwas über der Null-Linie angezeigt. Unten sieht es gut aus. Flackern tuts wie sau. :)

[ - Antworten - Zitieren - Direktlink - ]

10.09.2006, 03:36 Uhr

whose
Posts: 2156
Nutzer
@MaikG:

Die tv_secs solltest Du aber schon mit in den IORequest für die WAIT_UNTIL-Unit übernehmen, damit das hinhaut.

Schließlich bekommst Du da die Systemzeit, da gehören nach dem Boot mit Sicherheit schon einige Sekunden dazu. microsecs bedeutet ja "Millionstel Sekunde", nicht soundsoviel "Ticks" seit Start der Systemzeit o.Ä. Die Sekunden werden extra gezählt.

So wartet das Teil bis zum nächsten Auftreten von "0 tv_secs + x tv_microsecs + 125", was bei einem 32Bit-Zähler für die Sekunden schon mal eine Weile dauern kann :D

Grüße

--
---

:boing: µA1 PPC 750GX-800
:boing: A4000 PPC 604e-233

[ - Antworten - Zitieren - Direktlink - ]

10.09.2006, 03:47 Uhr

whose
Posts: 2156
Nutzer
@Mad_Dog:

Also, so recht kapiere ich nicht, weshalb das so langsam abläuft. Ich würds ja verstehen, wenn SetAPen() innerhalb der Schleife benutzt würde, aber so... ich hab hier n kleines Spiel laufen, das 64 32x32-Pixel-Tiles blittet, das läuft auch auf AGA schnell genug, so daß man den Bildaufbau kaum mitverfolgen kann.

Okay, ich blitte da aus einer Hintergrund-Bitmap ins Fenster, benutze also keinen temporären Rastport, aber so dramatisch sollte der RastPort die ganze Sache eigentlich nicht verlangsamen.

Sehr seltsam... testen kann ich das mangels Sampler leider nicht selbst :(

Grüße

--
---

:boing: µA1 PPC 750GX-800
:boing: A4000 PPC 604e-233

[ - Antworten - Zitieren - Direktlink - ]

10.09.2006, 13:31 Uhr

MaikG
Posts: 5172
Nutzer
>Die tv_secs solltest Du aber schon mit in den IORequest für die
>WAIT_UNTIL-Unit übernehmen, damit das hinhaut.

WaitUntil wird doch schon beim öffnen des timer.device
angegeben, dafür gibts gar kein extra IORequest.
Und vor dem öffnen kann ich ja nicht abfragen.


Monoscope scheint bei mir ein sinnvolles abbild des Eingangssignals
zu zeigen(Megalosound).

[ - Antworten - Zitieren - Direktlink - ]

10.09.2006, 13:49 Uhr

whose
Posts: 2156
Nutzer
@MaikG

Guggst Du!

code:
WHILE myseconds%<20
        POKEW tr& + tr_node% + IORequestio_Command%, TR_GETSYSTIME&
        junk& = DoIO&(tr&)

        mymicros&=PEEKL(tr& + tr_time% + tv_micro%)
        mysecs&=PEEKL(tr& + tr_time% + tv_secs%) REM So!

        POKEW tr& + tr_node% + IORequestio_Command%, TR_ADDREQUEST&
        
        POKEL tr& + tr_node% + tv_secs%, mysecs& REM und so!
        POKEL tr& + tr_time% + tv_micro%, mymicros&+125& REM 125=8000Hz

        SendIO&(tr&)
        INCR mycount%:IF mycount%=8000 THEN mycount%=0:INCR myseconds% rem :move rpS&,20,25:Text rpS&, SADD(TIME$+CHR$(0)),8
        REM bla%=goertzel%((PEEKB(&hBFE101) - 127)<<8)
        junk& = WaitIO&(tr&) REM junk% = finish_wait(tr&)
      WEND


Du solltest Dich noch mal kundig machen, wofür die Struktur-Einträge gut sind und was sie bedeuten.

Grüße

--
---

:boing: µA1 PPC 750GX-800
:boing: A4000 PPC 604e-233


[ Dieser Beitrag wurde von whose am 10.09.2006 um 14:07 Uhr geändert. ]

[ - Antworten - Zitieren - Direktlink - ]

10.09.2006, 18:25 Uhr

MaikG
Posts: 5172
Nutzer
>Guggst Du!

Danke, aber das macht auch nichts anderes als ewig warten.
Soll ja 20 Sekunden laufen, ist jetzt schon 3 Minuten her.



>POKEL tr& + tr_node% + tv_secs%, mysecs& REM und so!

muss tr_time% heissen, aber geht trotzdem nicht.


[ Dieser Beitrag wurde von MaikG am 10.09.2006 um 18:49 Uhr geändert. ]

[ - Antworten - Zitieren - Direktlink - ]

10.09.2006, 20:34 Uhr

whose
Posts: 2156
Nutzer
@MaikG:

Dann läuft irgendwo anders was schief. In C läuft ein ähnliches Programm, welches die UNIT_WAITUNTIL nutzt, problemlos und vor allem exakt.

Grüße

--
---

:boing: µA1 PPC 750GX-800
:boing: A4000 PPC 604e-233

[ - Antworten - Zitieren - Direktlink - ]

10.09.2006, 23:07 Uhr

MaikG
Posts: 5172
Nutzer
>Dann läuft irgendwo anders was schief. In C läuft ein ähnliches
>Programm, welches die UNIT_WAITUNTIL nutzt, problemlos und vor allem
>exakt.

Holger sagt bei Ihm läufts unter C auch nicht richtig.


Da ist noch die Function welche zum Timer zeugs gehört:

code:
FUNCTION create_timer&()
        STATIC r&, timerport&, timerIO&
        create_timer& = NULL&
        timerport& = CreateMsgPort&()
        IF timerport& <> NULL& THEN
            timerIO& = CreateIORequest&(timerport&, timerequest_sizeof%)
            IF timerIO& <> NULL& THEN
                r& = OpenDevice&(SADD("timer.device" + CHR$(0)), UNIT_WAITUNTIL&, timerIO&, 0)
                IF r& = 0 THEN create_timer& = timerIO& ELSE delete_timer timerIO&
            ELSE
                DeleteMsgPort timerport&
            END IF
        END IF
    END FUNCTION


[ - Antworten - Zitieren - Direktlink - ]

10.09.2006, 23:33 Uhr

whose
Posts: 2156
Nutzer
@MaikG:

Die hat aber mit der eigentlichen Timerfunktionalität wenig zu tun. Das ist den IORequest anlegen, timer.device öffnen etc. und wird nur einmal vor der Verwendung des timers durchlaufen.

Im Moment habe ich keinen Schimmer, was da bei Euch schiefläuft. Bei ihm mit dem C-Programm, bei Dir mit dem BASIC-Programm. Ich könnte verstehen, wenn sich das Problem bei größeren Zeiträumen bemerkbar machen würde, davor wird im RKM ja ausdrücklich gewarnt (das man dann besser UNIT_VBLANK einsetzt, weil deutlich stabiler über längere Perioden), aber bei 125µsek verstehe ich das nicht. Das liegt satt im Bereich der möglichen Auflösung und auch satt im Bereich der größten Stabilität der Timer.

Wenn alle Stricke reißen, werden wir wohl doch den Weg mit der direkten Timer-Benutzung gehen müssen (CIA übernehmen und einen der Zähler direkt nutzen) und dann schauen, was dann passiert.

Grüße

--
---

:boing: µA1 PPC 750GX-800
:boing: A4000 PPC 604e-233

[ - Antworten - Zitieren - Direktlink - ]

10.09.2006, 23:48 Uhr

MaikG
Posts: 5172
Nutzer
>Die hat aber mit der eigentlichen Timerfunktionalität wenig zu tun.
>Das ist den IORequest anlegen, timer.device öffnen etc. und wird nur
>einmal vor der Verwendung des timers durchlaufen.

Ja, aber das ist schon alles was mit den Timer zu tun hat
und ich sehe keinen Fehler.


>Wenn alle Stricke reißen, werden wir wohl doch den Weg mit der
>direkten Timer-Benutzung gehen müssen (CIA übernehmen und einen der
>Zähler direkt nutzen) und dann schauen, was dann passiert.

Ich find das mit den CIA ja nicht schlimm, oder ist das sehr
schwer? Ich mein, das ist sicherlich nicht AONE/Peg kompatibel
aber man hat ja beim CIA Timer die man legitim benutzen darf.

Ich wollte grade gucken wieviele, da sehe ich in Scout
das dieses Programm 251518:46'50.38 anfordert über die MicroHZ Unit.
Zum Vergleich bei Aweb steht 0:00'00.44 MicroHZ.

Kanns sein das es da noch eine Minutenvariable gibt die Initalisiert
werden muss?

[ - Antworten - Zitieren - Direktlink - ]

11.09.2006, 00:51 Uhr

whose
Posts: 2156
Nutzer
Zitat:
Original von MaikG:
>Die hat aber mit der eigentlichen Timerfunktionalität wenig zu tun.
>Das ist den IORequest anlegen, timer.device öffnen etc. und wird nur
>einmal vor der Verwendung des timers durchlaufen.

Ja, aber das ist schon alles was mit den Timer zu tun hat
und ich sehe keinen Fehler.


>Wenn alle Stricke reißen, werden wir wohl doch den Weg mit der
>direkten Timer-Benutzung gehen müssen (CIA übernehmen und einen der
>Zähler direkt nutzen) und dann schauen, was dann passiert.

Ich find das mit den CIA ja nicht schlimm, oder ist das sehr
schwer? Ich mein, das ist sicherlich nicht AONE/Peg kompatibel
aber man hat ja beim CIA Timer die man legitim benutzen darf.

Ich wollte grade gucken wieviele, da sehe ich in Scout
das dieses Programm 251518:46'50.38 anfordert über die MicroHZ Unit.
Zum Vergleich bei Aweb steht 0:00'00.44 MicroHZ.

Kanns sein das es da noch eine Minutenvariable gibt die Initalisiert
werden muss?


Öhm... ich seh grad, folgende Zeile:

POKEL tr& + tr_node% + tv_secs%, mysecs& REM und so!

muß so lauten:

POKEL tr& + tr_time% + tv_secs%, mysecs& REM und so!

Ich hab das heut mittag im Tran getippt, da ist mir dieser Fehler unterlaufen. Wenn wir tr_node verändern, geht das natürlich schief. Sch...-Sektparties immer :D Sorry nochmal.

Grüße

--
---

:boing: µA1 PPC 750GX-800
:boing: A4000 PPC 604e-233


[ Dieser Beitrag wurde von whose am 11.09.2006 um 01:01 Uhr geändert. ]

[ - Antworten - Zitieren - Direktlink - ]

11.09.2006, 09:34 Uhr

MaikG
Posts: 5172
Nutzer
>Ich hab das heut mittag im Tran getippt, da ist mir dieser Fehler
>unterlaufen. Wenn wir tr_node verändern, geht das natürlich schief.
>Sch...-Sektparties immer :D Sorry nochmal.

Den Fehler hatte ich nach kurzer Zeit gefunden, steht auch
oben, geht trotzdem nicht.


[ - Antworten - Zitieren - Direktlink - ]

11.09.2006, 10:20 Uhr

Mad_Dog
Posts: 1944
Nutzer
Zitat:
Original von whose:

testen kann ich das mangels Sampler leider nicht selbst :(


Naja... testen kannst Du's auch ohne Sampler - Du bekommst dann eben eine Flatline (Patient tot ;) ).


--
http://www.norman-interactive.com

[ - Antworten - Zitieren - Direktlink - ]

11.09.2006, 10:34 Uhr

Mad_Dog
Posts: 1944
Nutzer
Zitat:
Original von MaikG:

Ich find das mit den CIA ja nicht schlimm, oder ist das sehr
schwer? Ich mein, das ist sicherlich nicht AONE/Peg kompatibel
aber man hat ja beim CIA Timer die man legitim benutzen darf.


Du machst doch schon Low Level Zugriffe auf die CIA um den Parallelport abzufragen. Damit ist Dein Programm sowieso inkompatibel zu Maschinen ohne CIA.

Normalerweise sollten nur Treiber solche Low Level Zugriffe machen. Ein Anwendungsprogramm sollte immer auf des Betriebssystem aufsetzen und nicht auf die Hardware, wenn man "sauber" programmieren will.
--
http://www.norman-interactive.com

[ - Antworten - Zitieren - Direktlink - ]

11.09.2006, 12:54 Uhr

Holger
Posts: 8116
Nutzer
Zitat:
Original von whose:
@MaikG

Guggst Du!

code:
POKEL tr& + tr_time% + tv_secs%, mysecs& REM und so!
POKEL tr& + tr_time% + tv_micro%, mymicros&+125&


Äh, schon mal daran gedacht, dass beim Addieren der µs ein Überlauf stattfinden könnte? Und da TimeVal keine einfache 64-Bit-Zahl ist, sondern der µs-Wert nur bis 1Mio gehen darf, ist das Zusammenzählen auch keine triviale Addition. Man sollte einfach AddTime() benutzen. Ich hab's in meinem C-Programm benutzt, und es läuft. Na ja, bis auf die Tatsache, dass es insgesamt zu langsam läuft... Aber, nebenbei gesagt, mit anderen Zeitintervallen kann es durchaus auch zu schnell laufen, ganz wie Du meintest...

mfg
--
Good coders do not comment. What was hard to write should be hard to read too.

[ - Antworten - Zitieren - Direktlink - ]

11.09.2006, 13:14 Uhr

whose
Posts: 2156
Nutzer
Zitat:
Original von Holger:
Zitat:
Original von whose:
@MaikG

Guggst Du!

code:
POKEL tr& + tr_time% + tv_secs%, mysecs& REM und so!
POKEL tr& + tr_time% + tv_micro%, mymicros&+125&


Äh, schon mal daran gedacht, dass beim Addieren der µs ein Überlauf stattfinden könnte?

Ja, das wäre dann die nächste Stufe gewesen. Erst einmal wollte ich sehen, was da genau mit den Timern schiefgeht. Der "Überlauf" ist dabei nicht gar so tragisch, es timt dann nur etwas unregelmäßiger. Die fehlenden Sekunden waren erst einmal dringender, fand ich.

Zitat:
Und da TimeVal keine einfache 64-Bit-Zahl ist, sondern der µs-Wert nur bis 1Mio gehen darf, ist das Zusammenzählen auch keine triviale Addition. Man sollte einfach AddTime() benutzen. Ich hab's in meinem C-Programm benutzt, und es läuft. Na ja, bis auf die Tatsache, dass es insgesamt zu langsam läuft... Aber, nebenbei gesagt, mit anderen Zeitintervallen kann es durchaus auch zu schnell laufen, ganz wie Du meintest...

Und das ist es, was ich nicht verstehe... ich hab nun einiges mit den Timern gemacht und gerade bei diesen kleinen Zeiträumen keine großen Probleme mit der Genauigkeit der Timer gehabt. Bei größeren zu messenden Zeiträumen sieht das schon anders aus, ganz genau so, wie es in den RKMs beschrieben ist. Naja, noch ein bißchen mehr testen und suchen, würde ich sagen...

Grüße

--
---

:boing: µA1 PPC 750GX-800
:boing: A4000 PPC 604e-233

[ - Antworten - Zitieren - Direktlink - ]

11.09.2006, 13:40 Uhr

Holger
Posts: 8116
Nutzer
Kannst ja mal dieses Programm als Ausgangsbasis verwenden.
C code:
#define NULL 0
#define SAMPLING_RATE       (8000)
#define MAX_BINS            (12)
#define GOERTZEL_N          (92)

int    sample_count;
double q1[ MAX_BINS ];
double q2[ MAX_BINS ];
double r[ MAX_BINS ];

/*
 * coef = 2.0 * cos( (2.0 * PI * k) / (float)GOERTZEL_N)) ;
 * Where k = (int) (0.5 + ((float)GOERTZEL_N * target_freq) / SAMPLING_RATE));
 *
 * More simply: coef = 2.0 * cos( (2.0 * PI * target_freq) / SAMPLING_RATE );
 */
double coefs[ MAX_BINS ] = {
  1.7088388, 1.6339398, 1.5514226, 1.4616719,
  1.1533606, 1.0391679, 0.7968022, 0.5395935,
  -0.6697592, -1.0391679, -1.3651063, -1.7088388
};


/*----------------------------------------------------------------------------
 *  post_testing
 *----------------------------------------------------------------------------
 * This is where we look at the bins and decide if we have a valid signal.
 */
char* post_testing()
{
  int    row, col, see_digit;
  int    peak_count, max_index;
  double maxval, t;
  int    i;
  char   *row_col_ascii_codes[4][4] = {
         {"1", "2", "3", "A"},
         {"4", "5", "6", "B"},
         {"7", "8", "9", "C"},
         {"*", "0", "#", "D"}};


  /* Find the largest in the row group. */
  row = 0;
  maxval = 0.0;
  for( i=0; i<4; i++ )
  {
    if( r[i] > maxval )
    {
      maxval = r[i];
      row = i;
    }
  }

  /* Find the largest in the column group. */
  col = 4;
  maxval = 0.0;
  for( i=4; i<8; i++ )
  {
    if( r[i] > maxval )
    {
      maxval = r[i];
      col = i;
    }
  }

  /* Check for minimum energy */
  if( r[row] < 4.0e5 || r[col] < 4.0e5 )
  {
    /* energy not high enough */
    return NULL;
  }
  else
  {
    see_digit = 1;

    /* Twist check
     * CEPT => twist < 6dB
     * AT&T => forward twist < 4dB and reverse twist < 8dB
     *  -ndB < 10 log10( v1 / v2 ), where v1 < v2
     *  -4dB < 10 log10( v1 / v2 )
     *  -0.4  < log10( v1 / v2 )
     *  0.398 < v1 / v2
     *  0.398 * v2 < v1
     */
    if( r[col] > r[row] )
    {
      /* Normal twist */
      max_index = col;
      if( r[row] < (r[col] * 0.398) )    /* twist > 4dB, error */
          see_digit = 0;
    }
    else /* if( r[row] > r[col] ) */
    {
      /* Reverse twist */
      max_index = row;
      if( r[col] < (r[row] * 0.158) )    /* twist > 8db, error */
          see_digit = 0;
    }

    /* Signal to noise test
     * AT&T states that the noise must be 16dB down from the signal.
     * Here we count the number of signals above the threshold and
     * there ought to be only two.
     */
    if( r[max_index] > 1.0e9 )
        t = r[max_index] * 0.158;
    else
        t = r[max_index] * 0.010;

    peak_count = 0;
    for( i=0; i<8; i++ ) if( r[i] > t ) peak_count++;
    if( peak_count > 2 ) see_digit = 0;

    return see_digit? row_col_ascii_codes[row][col-4]: NULL;
  }
}

static char* NEED_MORE=(char*)1;

/* goertzel */
char* goertzel( int sample )
{
  double q0;
  int    i;

  if( sample_count < GOERTZEL_N )
  {
    sample_count++;
    for( i=0; i<MAX_BINS; i++ )
    {
        q0 = coefs[i] * q1[i] - q2[i] + sample;
        q2[i] = q1[i];
        q1[i] = q0;
    }
    return NEED_MORE;
  }
  else
  {
    for( i=0; i<MAX_BINS; i++ )
    {
      r[i] = (q1[i] * q1[i]) + (q2[i] * q2[i]) - (coefs[i] * q1[i] * q2[i]);
      q1[i] = 0.0;
      q2[i] = 0.0;
    }
    sample_count = 0;
    return post_testing();
  }
}

#include <proto/dos.h>
#include <proto/exec.h>
#define __NOLIBBASE__
#define TimerBase (tr->tr_node.io_Device)
#include <proto/timer.h>
#include <devices/timer.h>
#include <stdint.h>

struct timerequest *open_timer(long unit)
{
  struct MsgPort *port;
  struct timerequest *req;

  if(port = CreateMsgPort())
  {
    if(req=(struct timerequest*)CreateIORequest(port,sizeof(struct timerequest)))
    {
      if(0 == OpenDevice("timer.device", unit, (struct IORequest*)req, 0))
        return req;
      DeleteIORequest((struct IORequest*)req);
    }
    DeleteMsgPort(port);
  }
  return NULL;
}
void start_timer(struct timerequest *req,ULONG secs,ULONG micro)
{
  if(req)
  {
    req->tr_node.io_Command = TR_ADDREQUEST;
    req->tr_time.tv_secs  = secs;
    req->tr_time.tv_micro = micro;
    SendIO((struct IORequest *)req);
  }
}
void end_timer(struct timerequest *req)
{
  if(req)
  {
    WaitIO((struct IORequest *)req);
  }
}
void close_timer(struct timerequest *req)
{
  struct MsgPort *port;

  if (req)
  {
    CloseDevice((struct IORequest *)req);
    port = req->tr_node.io_Message.mn_ReplyPort;
    DeleteIORequest((struct IORequest *)req);
    DeleteMsgPort(port);
  }
}

int main(int x, char**y)
{
  struct timerequest *tr=open_timer(UNIT_WAITUNTIL);
  struct timeval target, offset={0, 125};// 1e6/8000

  if(!tr) { PrintFault(IoErr(), "Couldn't open timer.device"); return 10; }
  tr->tr_node.io_Command=TR_GETSYSTIME;
  DoIO(&tr->tr_node);
  target=tr->tr_time;
  char* decoded=NULL;
  int check=0;
  volatile uint8_t *parallel_out_mask=(uint8_t*)0xBFE301;
  volatile uint8_t *parallel=(uint8_t*)0xBFE101;
  *parallel_out_mask=0;
  int checkTime=target.tv_secs;
  while(!(SetSignal(0L,0L)&SIGBREAKF_CTRL_C))
  {
    AddTime(&target, &offset);
    start_timer(tr, target.tv_secs, target.tv_micro);
  //VPrintf("wait until { %ld, %ld }n", (ULONG*)&target);
    signed int sample=*parallel;
    char* _new=goertzel((sample-127)<<8);
    if(_new!=NEED_MORE && _new!=decoded)
      if((decoded=_new)) { PutStr(decoded); Flush(Output()); }
 #if 0
 // mark one second (at least, where it should be one)
    if(checkTime!=target.tv_secs)
    {
      end_timer(tr);
      VPrintf("target time { %ld, %ld }n", (ULONG*)&target);
      checkTime=target.tv_secs;
      tr->tr_node.io_Command=TR_GETSYSTIME;
      DoIO(&tr->tr_node);
      VPrintf("sys time { %ld, %ld }n", (ULONG*)&tr->tr_time);
      Flush(Output());
    }
    else
  #endif
      end_timer(tr);
  }
  PutStr("n");
  close_timer(tr);
  return 0;
}

Entsprechender Debug-Code ist drin, der zeigt, wo der timer selbst steht und auf welche Zeit das Programm gewartet hat. Solange die Schleife im Durchschnitt schneller als die Wartezeit ist, müsste das Programm aufgrund von WAITUNTIL den timer immer wieder einholen. In dem Moment, wo die beiden Zeiten langfristig auseinanderdriften, ist offensichtlich die Schleife zu langsam.

Das Problem: die Schleife scheint bei 125µs selbst dann zu langsam zu sein, wenn die Goertzel-Berechnung auskommentiert wird, d.h. außer Warten auf den timer nichts weiter passiert. Bei größeren Intervallen verhält sich das Programm korrekt, nur für's sampling ist das dann nicht mehr zu gebrauchen.

mfg
--
Good coders do not comment. What was hard to write should be hard to read too.

[ - Antworten - Zitieren - Direktlink - ]

11.09.2006, 16:44 Uhr

whose
Posts: 2156
Nutzer
@Holger:

Ich werde mir das Programm mal hier rausziehen und auf verschiedenen Systemen testen.

Das ulkige dabei ist, daß Deine Erfahrungen bezüglich der Langzeitstabilität der Geschichte genau umgekehrt zu meinen sind. Bei meinen Programmen war es bisher immer so, daß die Intervalle immer ungenauer eingehalten wurden, je größer das Zeitintervall gewählt wurde (positive und negative Drift machte sich bemerkbar, je nach Systemlast). Das deckt sich auch mit dem, was dazu im RKM "Devices" zu dem Thema gesagt wird. Sehr seltsam, das Ganze.

Grüße

--
---

:boing: µA1 PPC 750GX-800
:boing: A4000 PPC 604e-233

[ - Antworten - Zitieren - Direktlink - ]

11.09.2006, 16:53 Uhr

bubblebobble
Posts: 707
Nutzer
Der CIA timer wird bei Systemlast normalerweise nur schneller.
D.h. wenn die CPU längere Zeit 100% ausgelastet ist, z.B. bei Disk Zugriff ohne DMA. Das ist hier aber nicht der Fall.

Bei unserem Samplingproblem hier sollte das aber mehr oder weniger egal sein, zumindest nicht der grund warum es (bei MaikG) nicht funktioniert.

--
Thilo Köhler, Author von:
HD-Rec, Samplemanager, ArTKanoid, Monkeyscript, Toadies, AsteroidsTR, TuiTED, PosTED, TKPlayer, TKUnpacker
Homepage: http://www.hd-rec.de


[ - Antworten - Zitieren - Direktlink - ]

11.09.2006, 17:14 Uhr

whose
Posts: 2156
Nutzer
@Holger:

Öhm, mit welchem Compiler hast Du das eigentlich verwurstet? Der K&R-Stil bei den Definitionen in main() ist mir ja sofort aufgefallen, aber #include <stdint>? Hat doch ein "normaler" Amiga-68K-Compiler gar nicht unbedingt an Bord.

Abgesehen davon hängt es sich auf dem WinUAE weg, nachdem der Timer gestartet wurde und das Signal eintrifft (im Storm-Debugger sieht man aber sehr gut, daß das Signal wie gewünscht noch eintrudelt und auch noch registriert wird).

Naja, ich werd mal versuchen, im Laufe des Tages, da ein Ergebnis herauszubekommen.

Grüße

--
---

:boing: µA1 PPC 750GX-800
:boing: A4000 PPC 604e-233

[ - Antworten - Zitieren - Direktlink - ]

11.09.2006, 17:31 Uhr

Holger
Posts: 8116
Nutzer
Zitat:
Original von whose:
@Holger:

Öhm, mit welchem Compiler hast Du das eigentlich verwurstet? Der K&R-Stil bei den Definitionen in main() ist mir ja sofort aufgefallen, aber #include <stdint>? Hat doch ein "normaler" Amiga-68K-Compiler gar nicht unbedingt an Bord.


Das ist KEIN K&R Stil. Der K&R-Stil wäre so:
Even worse than C code:
int main(x, y)
int x, char**y;
{
...
}

Oder sogar so?
Even worse than C code:
main(x, y)
int x, char**y;
{
...
}


Mein Programm ist C99, übersetzbar mit vbcc, was ich als "normalen Amiga-68K-Compiler" bezeichnen würde. Außer gcc würde mir auch kein erwähnenswerter Compiler mehr einfallen, und der sollte das auch beherrschen.

mfg
--
Good coders do not comment. What was hard to write should be hard to read too.

[ - Antworten - Zitieren - Direktlink - ]

11.09.2006, 18:02 Uhr

whose
Posts: 2156
Nutzer
@Holger:

Also, ich hab den GCC auf Standardeinstellungen laufen, der übersetzt das nicht. Wäre mir irgendwo auch neu, daß Definitionen/Deklarationen "irgendwo im Code" unterstützt würden. Aber seis drum.

Ich habs jetzt soweit übersetzbar, dabei sind mir noch so ein paar Kleinigkeiten aufgefallen. CheckTime (bzw. der Vergleich darauf) ist witzlos. Die enthält sowieso target.tv_secs, wenn die ganze Sache zum Vergleich kommt. Es kommt also erst gar nicht zum Vergleich mit der Systemzeit. Auch egal, ich bau das jetzt mal so weit um, daß target-timeval und GETSYSTIME-timeval brav "nebeneinander" in einem Array landen und später platt ausgegeben werden.

Aufgefallen ist mir aber das, was Du meintest. Das Programm läuft enorm langsam, nie und nimmer im 125µs-Takt, wie es eigentlich sollte. Aus welchem Grund kann ich noch nicht sagen, das bleibt mir nach wie vor ein Rätsel. Wenn man sich die Werte mal mittels printf() ausgeben läßt, rast es nämlich förmlich durch, sogar die Takte hauen halbwegs hin (sofern man den Zeitaufwand von printf() überhaupt "Pi mal Daumen" abschätzen kann).

Es wird immer seltsamer :(

Nachtrag:

Inzwischen konnte ich mich näher mit dem Testprogramm beschäftigen. Die "Drift" zwischen Systemzeit und WAITUNTIL-Zeit ist ganz einfach zu erklären: Du hast vergessen, nach dem ersten Holen der Systemzeit target entsprechend in der while-Schleife zu setzen (auch in dem Teil, wo auf checkTime geprüft wird. Mach einfach die Bedingung immer wahr, dann siehst Du es).

Um die korrekte WAITUNTIL-Zeit zu bekommen, muß man sich vorher mittels TR_GETSYSTIME die aktuelle Systemzeit holen und dann erst die Differenz aufaddieren. Das fehlt in der while-Schleife, da addierst Du immer nur die Differenz auf die zu Beginn von main() gelesene SysTime, nicht auf die aktuelle. Daher driftet das auseinander, weil ja trotz allem immer ein wenig Zeit "verplempert" wird. Je länger das läuft, desto größer die "Drift" (die in Wirklichkeit gar keine ist).

Allein das end_timer() sorgt schon für kleinere Differenzen, der Goertzel für noch größere. Vor allem unterscheiden sich die Differenzen immer etwas, weil end_timer() nie ganz exakt gleich "wartet", bis der Request erledigt wurde. Auf einem "echten" Amiga würde das etwas geringer ausfallen, bei WinUAE macht sich die Last auf der Windows-Seite doch hin und wieder stärker bemerkbar, vor allem im Window-Mode von WinUAE.

Das erklärt übrigens auch, weshalb das auch ohne Goertzel und Textausgabe irgendwann einfach "durchrauscht". Die WAITUNTIL-Zeit ist ja, dank der "Drift" immer schon überschritten, wenn der Request gesendet wird. In der Folge kehrt das sofort zurück, statt 125µs zu warten.

Im Prinzip läuft der Timer daher exakt so, wie gewünscht. Für UNIT_MICROHZ spielt die Systemzeit aber keine Rolle.

2. braucht printf() (nicht Printf(), die läuft etwas schneller) auf meinem WinUAE-System ca. 20 tausendstel, um Text auszugeben. Das läßt sich dann prima ablesen. Sogar die Differenzen passen bis auf 2µs genau bei jedem Durchlauf.

Nun müßte ich mal mit dem Programm messen, wie lange der Goertzel braucht. Schätzungsweise dürfte der aber in 125µs durchgeackert sein, so daß das Timing im Grunde hinhaut.

Grüße

--
---

:boing: µA1 PPC 750GX-800
:boing: A4000 PPC 604e-233


[ Dieser Beitrag wurde von whose am 11.09.2006 um 20:11 Uhr geändert. ]

[ - Antworten - Zitieren - Direktlink - ]

11.09.2006, 22:55 Uhr

MaikG
Posts: 5172
Nutzer
>Du machst doch schon Low Level Zugriffe auf die CIA um den
>Parallelport abzufragen. Damit ist Dein Programm sowieso
>inkompatibel zu Maschinen ohne CIA.

Ja, genau muss auch nicht auf unechte Amiga HW laufen.


Muss nur noch ein gutes beispiel finden.

>Kannst ja mal dieses Programm als Ausgangsbasis verwenden.

Stürzt nur ab, vermutlich hab ichs falsch ins Basic übersetzt.

code:
dim offset&(1)

 WHILE myseconds%<20
            POKEW tr& + tr_node% + IORequestio_Command%, TR_GETSYSTIME&
            junk& = DoIO&(tr&)

            REM mymicros&=PEEKL(tr& + tr_time% + tv_micro%)
            REM mysecs&=  PEEKL(tr& + tr_time% + tv_secs%) REM So!
            offset&(0)=0:offset&(1)=125
	    target&=PEEKL(tr& + tr_time%)      
	    AddTime& target&, offset&(0)

            POKEW tr& + tr_node% + IORequestio_Command%, TR_ADDREQUEST&
            
            POKEL target& + tr_time% + tv_secs%, mysecs& REM und so!
            POKEL target& + tr_time% + tv_micro%, mymicros&+125& REM 125=8000Hz

            SendIO&(tr&)
            INCR mycount%:IF mycount%=8000 THEN mycount%=0:INCR myseconds% rem :move rpS&,20,25:Text rpS&, SADD(TIME$+CHR$(0)),8
            REM bla%=goertzel%((PEEKB(&hBFE101) - 127)<<8)
            junk& = WaitIO&(tr&) REM junk% = finish_wait(tr&)
          WEND




>Im Prinzip läuft der Timer daher exakt so, wie gewünscht. Für
>UNIT_MICROHZ spielt die Systemzeit aber keine Rolle.

Unit_MicroHZ geht genausowenig das war ja der 1.Versuch.

[ - Antworten - Zitieren - Direktlink - ]

11.09.2006, 23:27 Uhr

whose
Posts: 2156
Nutzer
@MaikG:

Zu dem BASIC-Code kann ich Dir relativ wenig sagen, weil ich MB nicht besitze. Eine Anmerkung habe ich aber:
code:
target&=PEEKL(tr& + tr_time%)


Das funktioniert nicht. target& muß eine timeval-Strukur sein, keine einfache 32-Bit-Zahl. Im C-Code funktioniert das, weil der C-Compiler Strukturen komplett kopieren kann. MB kann das nicht.

Du müßtest also mit PEEKL arbeiten, so wie in den von Dir auskommentierten Zeilen.

In der C-Variante läuft es (wenn auch nicht ganz so, wie es da steht), und die Timer-Events kommen zur vorgesehenen Zeit, wenn man das alles richtig sortiert.

Ich setz mich am Mittwoch mal dran und bau Mad_Dogs Programm so weit um, daß das Timing korrekt läuft und es verhältnismäßig leicht in BASIC übersetzbar ist (das ist bei seinen Programmen meist das geringste Problem, schön sauber und lesbar gehalten, wie ich finde). Testen müßt ihr das dann aber, weil ich keinen Sampler habe :D

Morgen müßte ich ein bißchen Zeit finden, um den Goertzel mal zu "messen". Dann sehe ich, ob das überhaupt direkt funktionieren kann oder ob wir doch ein Array mit den gesampleten Werten brauchen.

Grüße

--
---

:boing: µA1 PPC 750GX-800
:boing: A4000 PPC 604e-233

[ - Antworten - Zitieren - Direktlink - ]


Erste 1 2 3 4 5 -6- 7 8 9 10 11 [ - Beitrag schreiben - ]


amiga-news.de Forum > Programmierung > Tonerkennung [ - Suche - Neue Beiträge - Registrieren - Login - ]


.
Impressum | Datenschutzerklärung | Netiquette | Werbung | Kontakt
Copyright © 1998-2024 by amiga-news.de - alle Rechte vorbehalten.
.