DEUTSCHE VERSION |
|
Links | | | Forums | | | Comments | | | Report news |
Chat | | | Polls | | | Newsticker | | | Archive |
amiga-news.de Forum > Programmierung > Tonerkennung | [ - Search - New posts - Register - Login - ] |
First 3 4 5 6 7 -8- 9 10 11 | [ - Post reply - ] |
2006-09-13, 11:54 h Mad_Dog Posts: 1944 User |
Zitat: Bleibt die Frage zu klären was in folgendem Fall passiert: 1. Hole die aktuelle Systemzeit - nennen wir diesen Zeitpunkt t_0 2. Berechne Zeitpunkt t_0 + gewünschte Wartezeit - nennen wir diesen Zeitpunkt t_1 3. Mach irgendwas (z.B. Parrallelport auslesen, Berechnungen anstellen...) 4. Warte bis zum Zeitpunkt t_1 Wenn in 4. der Zeitpunkt t_1 bereits überschritten ist, müsste AFAIK eine dieser "Warte Bis" Funktionen des timer.device das Warten trotzdem beenden, da dieser Zeitpunkt t_1 ja nie mehr erreicht werden kann, weil schon vorbei... -- http://www.norman-interactive.com [ Dieser Beitrag wurde von Mad_Dog am 13.09.2006 um 11:55 Uhr geändert. ] [ - Answer - Quote - Direct link - ] |
2006-09-13, 11:58 h Holger Posts: 8116 User |
Zitat:Eine Variable da zu deklarieren, wo sie gebraucht wird, statt irgendwo am Anfang von irgendetwas, ist das normalste von der Welt. So halten es C++, C99, Java und noch diverse andere Programmiersprachen, die nicht in den Denkmustern aus den 80ern, bzw. man müsste ja bei C eher 70ern stehengeblieben sind. Zitat:Ja, ich hatte das Programm mehrfach umgestellt, von µHZ auf EClock, Wait... und zurück. Da habe ich wohl vor lauter "the same as" in den Autodocs die Falle übersehen. Ja ja, die Leute bei Commodore wussten halt, was Spass macht. Zitat:Vollkommen richtig, aber wenn man in der Schleife alles entfernt, was Overhead erzeugen könnte, rutschen SendIO und WaitIO sowieso direkt hintereinander, weil dazwischen ja nichts mehr passiert. Deshalb kann man es dann auch durch DoIO ersetzen. mfg -- Good coders do not comment. What was hard to write should be hard to read too. [ - Answer - Quote - Direct link - ] |
2006-09-13, 11:59 h whose Posts: 2156 User |
Zitat: Das tun sie auch. UNIT_WAITUNTIL gibt allerdings erst mit dem nächsten VBLANK Laut, was in den meisten Fällen viel zu spät sein dürfte. Daher kommt auch die Annahme, daß die Timer viel zu langsam laufen würden. Maik arbeitet nun aber mit reinem Polling, wenn ich das recht verstanden habe, das ist naturgemäß etwas schwieriger zu handhaben. Grüße -- --- µA1 PPC 750GX-800 A4000 PPC 604e-233 [ - Answer - Quote - Direct link - ] |
2006-09-13, 12:05 h whose Posts: 2156 User |
Zitat: Dann bleibe ich ehrlich gesagt lieber bei der Lesbarkeit der 70er, als mich da in die 90er zu begeben. Zitat:Zitat:Ja, ich hatte das Programm mehrfach umgestellt, von µHZ auf EClock, Wait... und zurück. Da habe ich wohl vor lauter "the same as" in den Autodocs die Falle übersehen. Ja ja, die Leute bei Commodore wussten halt, was Spass macht. Komisch... ich habe das auf Anhieb gefunden und sofort gesehen, welche Unit mit welcher Granularität arbeitet. Steht direkt bei den Beschreibungen zu den Units im RKM. Auch in den Autodocs ist das recht klar ersichtlich, finde ich. Nun ja, also bauen wir (bzw. ich) das Ganze mal für den Anfang mit UNIT_MICROHZ, später dann in einer Fassung mit UNIT_WAITECLOCK. Und ich wette, daß das problemlos (mit Abweichungen +- 3-4µs) funktioniert. Grüße -- --- µA1 PPC 750GX-800 A4000 PPC 604e-233 [ - Answer - Quote - Direct link - ] |
2006-09-13, 12:08 h Mad_Dog Posts: 1944 User |
Zitat:Zitat:Vollkommen richtig, aber wenn man in der Schleife alles entfernt, was Overhead erzeugen könnte, rutschen SendIO und WaitIO sowieso direkt hintereinander, weil dazwischen ja nichts mehr passiert. Deshalb kann man es dann auch durch DoIO ersetzen. Wobei Du in Deinem Beispiel ja kein WaitIO(), Wait(), WaitPort() oder sonst was drin hast. Was dabei herauskommt könnte man eine "Denial of Service Attacke" auf das timer.device nennen. Du bombst das timer.device nur mit Anfragen zu, ohne zu warten... Ich weiß jetzt nicht auswendig, wo all diese Anfragen landen - möglicherweise in einer Queue. Und was passiert, wenn diese Queue voll ist? -- http://www.norman-interactive.com [ Dieser Beitrag wurde von Mad_Dog am 13.09.2006 um 12:10 Uhr geändert. ] [ - Answer - Quote - Direct link - ] |
2006-09-13, 12:39 h Holger Posts: 8116 User |
Zitat: Nein, hast Du nicht. Du hast zwei Tage lange Schwachsinn darüber, dass man das Programm "kalibrieren" müsste geredet, bevor Du den Fehler gefunden hast. Dass das Programm von mir einen Fehler hatte, war bekannt, jedenfall bevor Du damit angefangen hast, dass das timer.device angeblich so funktionieren würde, dass wait until nicht mehr wait until, sondern wait something mystical bedeuten würde. Hättest Du vor zwei Tagen diesen Fehler gefunden, wäre ich Dir dankbar gewesen. So hast Du zwei Tage lang meine Zeit verschwendet, wo das Ändern des Beispiels von WAIT_UNTIL auf WAIT_ECLOCK eine Sache von fünf Minuten gewesen wäre. Aber Du wolltest lieber die Logik des Programms in Frage stellen, statt nach einem einfachen Fehler Suchen zu helfen. mfg -- Good coders do not comment. What was hard to write should be hard to read too. [ - Answer - Quote - Direct link - ] |
2006-09-13, 12:42 h Holger Posts: 8116 User |
Zitat: Wie kommst Du denn darauf? DoIO() macht (fast) exakt das gleiche wie SendIO(), gefolgt von WaitIO(). Der einzige Unterschied ist, dass über das IOF_QUICK Flag dem device mitgeteilt wird, dass es diese Anfrage auch synchron ausführen könnte. Was aber in diesem speziellen Fall vom timer.device ignoriert wird. mfg -- Good coders do not comment. What was hard to write should be hard to read too. [ - Answer - Quote - Direct link - ] |
2006-09-13, 13:09 h Holger Posts: 8116 User |
Klasse, jetzt sind eClock und Programm perfekt in Sync. Die reale Zeit ist es zwar nicht, aber das würde ich bei einem Emulator auch nicht zwingend erwarten.C code:Ich weiß, echte Männer programmieren sich ihre 64Bit-Arithmetik selbst, ich habe stattdessen auf den C99-Modus zurückgegriffen...#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 close_timer(struct timerequest *req) { struct MsgPort *port; 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_WAITECLOCK); ULONG ticksPerSecond=8000, eclockPerSec, eclockPerTick, sec, i; uint64_t target, startTime; if(!tr) { PrintFault(IoErr(), "Couldn't open timer.device"); return 10; } eclockPerTick=ReadEClock((struct EClockVal*)&startTime)/ticksPerSecond; target=startTime; tr->tr_node.io_Command = TR_ADDREQUEST; for(i=0; !(SetSignal(0L,0L)&SIGBREAKF_CTRL_C); i++) { target+=eclockPerTick; tr->tr_time=*(struct timeval*)⌖ DoIO((struct IORequest *)tr); } eclockPerSec=ReadEClock((struct EClockVal*)&tr->tr_time); VPrintf("processed %ld requestsn", (ULONG*)&i); sec=(target-startTime)/eclockPerSec; VPrintf("elapsed target time %ld sn", &sec); sec=(*((uint64_t*)&tr->tr_time)-startTime)/eclockPerSec; VPrintf("elapsed sys time %ld sn", &sec); close_timer(tr); return 0; } mfg -- Good coders do not comment. What was hard to write should be hard to read too. [ - Answer - Quote - Direct link - ] |
2006-09-13, 13:20 h Holger Posts: 8116 User |
Zitat:Also mal ein Vorschlag. Schreibe Dein Programm so um, dass es die Samples auf einer Datei liest. Erzeuge mit irgendeiner Sampling-Software eine Datei, in der definitiv ein paar Töne enthalten sind, und versuche diese zu analysieren. So hab ich das auch zuerst gemacht, deshalb weiß ich ja, dass mein System genug Reserven zur Berechnung hat, natürlich auch, weil ich keinen Sampler habe. Aber dann kannst Du sehen, ob ein realer Amiga das packt, und wie schnell er es schafft, wenn er nicht mit der Realzeit synchronisiert laufen muss. Da Du eine andere Version des DTMF-Codes benutzt hast, kann es natürlich auch sein, dass diese fehlerhaft ist... mfg -- Good coders do not comment. What was hard to write should be hard to read too. [ - Answer - Quote - Direct link - ] |
2006-09-13, 16:02 h gni Posts: 1106 User |
Zitat:IMHO sollten proto/ Header immer nach nach NDK-Headern kommen. Zitat:Und Du meinst wirklich das all die Casts ganz harmlos sind? Der letzte ist besonders übel. Echte Männer können das wesentlich besser.C code:Ich weiß, echte Männer programmieren sich ihre 64Bit-Arithmetik selbst, ich habe stattdessen auf den C99-Modus zurückgegriffen...uint64_t target, startTime; ... eclockPerTick=ReadEClock((struct EClockVal*)&startTime)/ticksPerSecond; ... tr->tr_time=*(struct timeval*)⌖ DoIO((struct IORequest *)tr); ... eclockPerSec=ReadEClock((struct EClockVal*)&tr->tr_time); ... sec=(*((uint64_t*)&tr->tr_time)-startTime)/eclockPerSec; Zitat:Wofür ist der Cast bei &i gut?C code:VPrintf("processed %ld requestsn", (ULONG*)&i); [ - Answer - Quote - Direct link - ] |
2006-09-13, 18:12 h Mad_Dog Posts: 1944 User |
Zitat: Wenn man vom Teufel spricht: http://www.amiganews.de/forum/thread.php?id=24044&BoardID=14 -- http://www.norman-interactive.com [ - Answer - Quote - Direct link - ] |
2006-09-13, 18:18 h Holger Posts: 8116 User |
Zitat:Hey komm, der letzte hat mir eine Variable eingespart, immerhin ganze 8 bytes! Um typecasts kommst Du an der Stelle trotzdem nicht drumrum, ReadEClock erwartet nunmal ein struct EClockVal und kein 64Bit-int, abgesehen davon, dass TimeRequest immer eine TimeVal-Struktur eingebettet hat, selbst dann, wenn man UNIT_ECLOCK oder UNIT_WAITECLOCK benutzt, also die Struktur eigentlich EClockVal sein müsste. Zitat:Ja, die Variable hatte ursprünglich einen anderen Typ. Kann man natürlich weglassen... mfg -- Good coders do not comment. What was hard to write should be hard to read too. [ - Answer - Quote - Direct link - ] |
2006-09-13, 18:26 h MaikG Posts: 5172 User |
>Wenn in 4. der Zeitpunkt t_1 bereits überschritten ist, müsste AFAIK >eine dieser "Warte Bis" Funktionen des timer.device das Warten >trotzdem beenden, da dieser Zeitpunkt t_1 ja nie mehr erreicht werden >kann, weil schon vorbei... Ja wenn new-old>124 wird rausgegangen. >Das tun sie auch. UNIT_WAITUNTIL gibt allerdings erst mit dem >nächsten VBLANK Laut, was in den meisten Fällen viel zu spät sein >dürfte. Daher kommt auch die Annahme, daß die Timer viel zu langsam >laufen würden. Ich hab aber MicroHZ und nicht Waituntil verwendet. >Maik arbeitet nun aber mit reinem Polling, wenn ich das recht >verstanden habe, das ist naturgemäß etwas schwieriger zu handhaben. Das ist nur eine von vielen Varianten die ich probiert habe, welche halbwegs schneller als die anderen ist. >Also mal ein Vorschlag. >Schreibe Dein Programm so um, dass es die Samples auf einer Datei >liest. Erzeuge mit irgendeiner Sampling-Software eine Datei, in der >definitiv ein paar Töne enthalten sind, und versuche diese zu >analysieren. Ja, okay das könnte ich mal versuchen. >Da Du eine andere Version des DTMF-Codes benutzt hast, kann es >natürlich auch sein, dass diese fehlerhaft ist... Hast du den Code nicht zuletzt noch überprüft und was geändert? [ - Answer - Quote - Direct link - ] |
2006-09-14, 13:23 h Holger Posts: 8116 User |
Zitat:Ich?! Nein, ich habe lediglich hier den Link auf Wikipedia gepostet, dann den code runtergeladen und ein Amiga-Programm drumherum gestrickt, das ein Sample analysiert, um ihn auszuprobieren. Währenddessen hat jemand auf Wikipedia eine Änderung gemacht (nicht ich), die insgesamt sinnvoll erscheint, die ich bislang aber nicht ausprobiert habe. Und Du hast die geänderte Version als Ausgangsbasis verwendet. Ich gehe zwar davon aus, dass normalerweise keiner ungetesten code auf Wikipedia legt, aber ich hab schon so manches erlebt, das ich nicht für normal gehalten hätte. Deshalb sag ich ja, probier Deinen code erst mal mit nem Sample. Evtl. hast Du ja auch beim Übersetzen in Basic noch Fehler eingebaut. Wenn klar ist, dass die Analyse funktioniert, kann man immer noch die beiden anderen Fehlerquellen, Parallelport und Timer, hinzufügen. mfg -- Good coders do not comment. What was hard to write should be hard to read too. [ - Answer - Quote - Direct link - ] |
2006-09-14, 18:04 h MaikG Posts: 5172 User |
>Ich?! Ja klick unten auf 4, 6.Post. [ - Answer - Quote - Direct link - ] |
2006-09-14, 18:48 h Holger Posts: 8116 User |
Zitat: Ach das meinst Du. Ja, da habe ich nur ein wenig aufgeräumt, ohne die Logik des Programms zu verändern. Und ich habe auch ein Auge darauf geworfen, dass es dem (aktuelleren) C-Programm entspricht. Aber zum einen kann ich dabei auch etwas übersehen haben, zum anderen habe ich es mangels Samplers und wegen des timing-Problems nicht getestet. Hätte ich es schon zum Testen umgeschrieben, damit es mit Dateien klar kommt, hätte ich diese Version auch hier gepostet, statt Dir zu sagen, dass Du das mal machen sollst... mfg -- Good coders do not comment. What was hard to write should be hard to read too. [ - Answer - Quote - Direct link - ] |
2006-09-14, 22:21 h MaikG Posts: 5172 User |
>Ja, da habe ich nur ein wenig aufgeräumt, ohne die Logik des >Programms zu verändern. Naja, seitdem zeigt das Programm gar nichts mehr an, davor immer irgendwelche sachen, manchmal traf das halt zu. [ - Answer - Quote - Direct link - ] |
2006-09-15, 16:36 h Holger Posts: 8116 User |
Zitat: Manchmal zutreffen hilft Dir auch nicht weiter. Ich hab das jetzt soweit testen können, dass ich Dir sagen kann, dass Deine Umsetzung des Algorithmus funktioniert. Das Problem lag in der Vorzeichenbehandlung, also da wo in meiner Fassung steht code:müsste mansa%=( PEEKB(&hBFE101) - 127 )<<8 bla%=goertzel%(sa%) code:schreiben.sa&=PEEKB(&hBFE101)<<8 IF sa&>&H7FFF THEN sa&=sa& OR &HFFFF0000& bla%=goertzel%(sa&) Hier mal das Programm, das 'ne Datei analysiert. Die Testdatei ist allerdings eine 16Bit 48kHz WAV-Datei, kein 8Bit 8kHz, den Teil bei der I/O müsste man abändern, wenn man andere Dateien testen will. Basic code:Von der Performance her durchaus mit dem C-Program vergleichbar.REM aktualisiert 04.09.2006 - 16:00 REM $Nolibrary REM $Nolines REM $NoOverflow REM $NOEVENT DEFINT A-Z '$INCLUDE Exec.bh '$INCLUDE Dos.bh LIBRARY OPEN "exec.library", LIBRARY_MINIMUM& LIBRARY OPEN "dos.library", LIBRARY_MINIMUM& DIM SHARED junk&,dummy$ CONST SAMPLING_RATE%=8000 CONST MAX_BINS%=8 CONST GOERTZEL_N%=92 DIM SHARED q1#(MAX_BINS%) 'double q1[ MAX_BINS ]; DIM SHARED q2#(MAX_BINS%) 'double q2[ MAX_BINS ]; DIM SHARED r#(MAX_BINS%) 'double r[ MAX_BINS ]; DIM SHARED freqs#(MAX_BINS%) DIM SHARED sample_count% 'INT sample_count; DIM SHARED coefs#(MAX_BINS%) DIM SHARED row_col_ascii_codes$(4,4) freqs#(0)=697 freqs#(1)=770 freqs#(2)=852 freqs#(3)=941 freqs#(4)=1209 freqs#(5)=1336 freqs#(6)=1477 freqs#(7)=1633 row_col_ascii_codes$(0,0)="1" row_col_ascii_codes$(0,1)="2" row_col_ascii_codes$(0,2)="3" row_col_ascii_codes$(0,3)="A" row_col_ascii_codes$(1,0)="4" row_col_ascii_codes$(1,1)="5" row_col_ascii_codes$(1,2)="6" row_col_ascii_codes$(1,3)="B" row_col_ascii_codes$(2,0)="7" row_col_ascii_codes$(2,1)="8" row_col_ascii_codes$(2,2)="9" row_col_ascii_codes$(2,3)="C" row_col_ascii_codes$(3,0)="*" row_col_ascii_codes$(3,1)="0" row_col_ascii_codes$(3,2)="#" row_col_ascii_codes$(3,3)="D" REM SUB calc_coeffs FOR n%=0 TO 7 REM MAX_BINS%-1 coefs#(n%)=2.0*COS(2.0*3.141592654 * freqs#(n%)/SAMPLING_RATE%) NEXT n% REM END SUB ' post_testing ' This is where we look at the bins and decide if we have a valid signal. FUNCTION post_testing$ STATIC row%, col%, see_digit% STATIC peak_count%, max_index%, i% STATIC maxval#,t# post_testing$="" ' /* Find the largest in the row group. */ row%=0 maxval#=0.0 FOR i%=0 TO 3 IF r#(i%)>maxval# THEN maxval#=r#(i%):row%=i% NEXT i% ' /* Find the largest in the column group. */ col%=4 maxval#=0.0 FOR i%=4 TO 7 IF r#(i%)>maxval# THEN maxval#=r#(i%):col%=i% NEXT i% ' /* Check FOR minimum energy */ IF r#(row%)<4E5 OR r#(col%)<4E5 THEN 2 see_digit%=TRUE& IF r#(col%)>r#(row%) THEN max_index%=col% IF r#(row%)<(r#(col%)*0.398) THEN see_digit% = FALSE& REM twist > 4dB, error ELSE max_index%=row% IF r#(col%)<(r#(row%)*0.158) THEN see_digit% = FALSE& REM twist > 8db, error END IF IF r#(max_index%)>1E9 THEN t#=r#(max_index%)*0.158 ELSE t#=r#(max_index%)*0.010 peak_count%=0 FOR i%=0 TO 7 IF r#(i%)>t# THEN INCR peak_count% NEXT i% IF peak_count%>2 THEN see_digit%=FALSE& IF see_digit% THEN post_testing$=row_col_ascii_codes$(row%,col%-4) 2 END FUNCTION ' * goertzel FUNCTION goertzel$(sample%) STATIC q0#, i% REM IF sample%<>0 THEN ? "sample: ";sample%;" "; IF sample_count%<GOERTZEL_N% THEN INCR sample_count% FOR i%=0 TO 7 REM MAX_BINS%-1 q0#=coefs#(i%)*q1#(i%)-q2#(i%)+sample% q2#(i%)=q1#(i%) q1#(i%)=q0# NEXT i% goertzel$="." ' need more ELSE FOR i%=0 TO 7 REM MAX_BINS%-1 r#(i%)=q1#(i%)*q1#(i%) + q2#(i%)*q2#(i%) - coefs#(i%)*q1#(i%)*q2#(i%) q1#(i%)=0.0 q2#(i%)=0.0 NEXT i% goertzel$=post_testing$ sample_count%=0 END IF END FUNCTION file&=xOpen(SADD("work:code/dtmf/Dtmf_example.wav"+CHR$(0)), MODE_OLDFILE&) IF file&=NULL& THEN PRINT "opening file failed": GOTO 5 REM skipping wave header dummy&=Seek&(file&, 48, OFFSET_CURRENT%) num&=0 WHILE INKEY$<>CHR$(27) REM reading 16 Bit value a&=FGetC(file&):b&=FGetC(file&) IF (a& OR b&) == -1 THEN 4 sample&=(b&<<8) OR c& IF b&>127 THEN sample&=sample& OR &hffff0000& INCR num& cur$=goertzel$(sample&) IF cur$<>"." AND cur$<>last$ THEN last$=cur$: ? last$; FOR i%=0 TO 4 ' Skipping 5 16Bit values to convert 48kHz to 8kHz c&=FGetC(file&):d&=FGetC(file&) IF (c& OR d&) == -1 THEN 4 NEXT WEND 4 dummy&=xClose(file&) ?:?"proc";num&8000!;" sec" 5 END mfg -- Good coders do not comment. What was hard to write should be hard to read too. [ - Answer - Quote - Direct link - ] |
2006-09-15, 17:56 h MaikG Posts: 5172 User |
>Manchmal zutreffen hilft Dir auch nicht weiter. Stimmt. >Ich hab das jetzt soweit testen können, dass ich Dir sagen kann, >dass Deine Umsetzung des Algorithmus funktioniert. Immerhin... >Das Problem lag in der Vorzeichenbehandlung Mh, dann werd ich die mal ändern und im ungenauen Timing testen. >Hier mal das Programm, das 'ne Datei analysiert. Die Testdatei ist >allerdings eine 16Bit 48kHz WAV-Datei, kein 8Bit 8kHz, den Teil bei >der I/O müsste man abändern, wenn man andere Dateien testen will. Macht nix hab ja eine Toccata, werd ich nachher mal Probieren. >Von der Performance her durchaus mit dem C-Program vergleichbar. Mein ich ja an MB liegt das nicht, es ist nur unter gewissen umständen langsamer als C und die treffen hier nicht zu. [ - Answer - Quote - Direct link - ] |
2006-09-15, 19:51 h MaikG Posts: 5172 User |
Da gabs eine Zeile die hiess: IF r#(row%)>=4E5 AND r#(col%)>=4E5 THEN see_digit% = TRUE& jetzt: IF r#(row%)<4E5 OR r#(col%)<4E5 THEN GOTO 2 Nun bekomme ich wieder meine Fantasiewerte, auch mit neuen Sampler zugriff :-) Das ist nur eine abweichung bei 20s hinter der Kommastelle und das Prog liefert sonstwas. Das Prg. was von der Datei liesst Funktioniert genau so wie es soll. 8 Sekunden sagt es. Ich hab mal 9876543210*# auf dem Handy getippt und das kam auch raus, keine werte dazwischen, keine Falschen... [ - Answer - Quote - Direct link - ] |
2006-09-16, 19:06 h whose Posts: 2156 User |
@Holger: (Bullshit bzgl. der Laufzeiten von GetMsg() entfernt). Ich habe ein wenig experimentiert und auf meinem WinUAE-System geht es mittels WAITECLOCK-Unit problemlos. Die Abweichungen, die man bei kleineren Frequenzen bekommt, stammen übrigens von GetSysTime, welches auch ein wenig braucht. Also UNIT_WAITECLOCK benutzen. Grüße [ Dieser Beitrag wurde von whose am 16.09.2006 um 20:42 Uhr geändert. ] [ - Answer - Quote - Direct link - ] |
2006-09-16, 21:14 h whose Posts: 2156 User |
Und hier das dazugehörige Programm. Es ist "auf die Schnelle" zusammengestrickt, während ich bei einem Kunden war. Falls da ein dicker Patzer drin sein sollte, bitte ich im Voraus schon einmal um größte Vergebung. Ich denke aber, daß das Ding soweit ok ist, logische Fehler sollten keine drin sein. Die Verzögerungen, die sich manchmal ergeben, scheinen tatsächlich von GetSysTime() herzurühren. Hat jemand Informationen über die Granularität dieser Funktion? Ich habe das Gefühl, daß die über den VBlank aktuell gehalten wird. Abgesehen davon: Kann es sein, daß da irgendwo noch ein Task-Switch dazwischenfunkt? Diese Merkwürdigen Zahlen, die sich da manchesmal ergeben, zwischen 20000 und 40000 µs zum Beispiel, kommen mir etwas "unheimlich" vor. C code:/* ----------------------------------------------------------------------------- Testprogramm für die Funktion der UNIT_WAITECLOCK des timer.device */ #ifdef __amigaos4__ #define __USE_INLINE__ #endif #include <stdio.h> #include <exec/exec.h> #include <exec/ports.h> #include <exec/libraries.h> #include <dos/dos.h> #include <devices/timer.h> #include <proto/dos.h> #include <proto/exec.h> struct timerequest *TimerIO; struct MsgPort *TimerMP; struct Message *TimerMsg; struct Library *TimerBase; int main(void) { struct timeval ref1, ref2; struct EClockVal eclockval; unsigned long intervall, ticks; long diff; LONG error; unsigned int repeat = 0; TimerMP = (struct MsgPort *)CreatePort(NULL, 0); if(!TimerMP) { printf("Konnte Timer-Port nicht anlegen!n"); exit(RETURN_FAIL); } TimerIO = (struct timerequest *)CreateExtIO(TimerMP, sizeof(struct timerequest)); if(!TimerIO) { printf("Konnte Timer-IORequest nicht anlegen!n"); exit(RETURN_FAIL); } error = OpenDevice(TIMERNAME, UNIT_WAITECLOCK, (struct IORequest *)TimerIO, 0L); if(error) { printf("Konnte timer.device nicht öffnen!n"); exit(RETURN_FAIL); } TimerBase = (struct Library *)TimerIO->tr_node.io_Device; printf("Gewünschtes Intervall in Hz: "); scanf("%lu", &intervall); ticks = ReadEClock(&eclockval); diff = ticks / intervall; /* Normal müßte man auf - testen */ printf("Hi: %lu Lo: %lun", eclockval.ev_hi, eclockval.ev_lo); /* sehr simpler Überlauf-Test */ if( ((eclockval.ev_lo) + diff) < eclockval.ev_lo) { eclockval.ev_hi++; } else { eclockval.ev_lo += diff; } //printf("New Hi: %lu New Lo: %lun", eclockval.ev_hi, eclockval.ev_lo); TimerIO->tr_node.io_Command = TR_ADDREQUEST; TimerIO->tr_time.tv_secs = eclockval.ev_hi; TimerIO->tr_time.tv_micro = eclockval.ev_lo; SendIO((struct IORequest *)TimerIO); GetSysTime(&ref1); while(repeat < intervall) { TimerMsg = WaitPort(TimerMP); /* Vorsicht, wilde Überläufe ;) */ if( ((eclockval.ev_lo) + diff) < eclockval.ev_lo) { eclockval.ev_hi++; } else { eclockval.ev_lo += diff; } TimerIO->tr_node.io_Command = TR_ADDREQUEST; TimerIO->tr_time.tv_secs = eclockval.ev_hi; TimerIO->tr_time.tv_micro = eclockval.ev_lo; SendIO((struct IORequest *)TimerIO); /* hier was sinnvolles tun, sofern vorhanden */ repeat++; } GetSysTime(&ref2); AbortIO((struct IORequest *)TimerIO); WaitIO((struct IORequest *)TimerIO); CloseDevice((struct IORequest *)TimerIO); DeleteExtIO((struct IORequest *)TimerIO); DeletePort(TimerMP); printf("n"); printf("Intervall(EClock-ticks): %ldn", ticks / intervall); printf("Referenz 1: %ld %ldn", ref1.tv_secs, ref1.tv_micro); printf("Referenz 2: %ld %ldn", ref2.tv_secs, ref2.tv_micro); SubTime(&ref2, &ref1); printf("Differenz: %9ld %ldn", ref2.tv_secs, ref2.tv_micro); exit(RETURN_OK); } Grüße -- --- µA1 PPC 750GX-800 A4000 PPC 604e-233 [ Dieser Beitrag wurde von whose am 16.09.2006 um 21:16 Uhr geändert. ] [ Dieser Beitrag wurde von whose am 17.09.2006 um 02:48 Uhr geändert. ] [ Dieser Beitrag wurde von whose am 17.09.2006 um 22:28 Uhr geändert. ] [ - Answer - Quote - Direct link - ] |
2006-09-17, 13:08 h Holger Posts: 8116 User |
@whose: Nur eine Frage, so beim Überfliegen: Wieso hält sich eigentlich hartnäckig die Verwendung der AOS1.x Supportlib-Funktionen, wo es seit AOS2.0 die Funktionen CreateMsgPort() und CreateIORequest() gibt? Ich mein, bei einem Programm, das mit #ifdef __amigaos4__ anfängt, erscheint mir das irgendwie unangemessen. Ist zwar hier nicht wichtig, scheint aber irgendwie in die Gewohnheiten- Richtung zu gehen, mir fällt das irgendwie immer wieder hier auf. mfg -- Good coders do not comment. What was hard to write should be hard to read too. [ - Answer - Quote - Direct link - ] |
2006-09-17, 13:18 h whose Posts: 2156 User |
Zitat: Upps, ja da hast Du Recht. Ich sag ja, das war auf die Schnelle zusammengestrickt und CreateExtIO() ist tatsächlich eine blöde Angewohnheit. Das #ifdef __amigaos4__ stammt von Cubic und ich habs dringelassen, für den Fall, daß das jemand auf so einer Maschine mal testen mag. Ich versuche, mir CreateExtIO() & Co. abzugewöhnen Grüße -- --- µA1 PPC 750GX-800 A4000 PPC 604e-233 [ - Answer - Quote - Direct link - ] |
2006-09-17, 13:18 h Holger Posts: 8116 User |
Zitat:Die Schlussfolgerung hatte ich auch schon ;-) Schließlich macht mein Programm oben (mit UNIT_WAITECLOCK) ja auch schon das richtige. Es weicht halt nur von der Echtzeit ab, messbar für das Programm nur in dem Fall, wenn der Emulator die Echtzeit-Uhr auch mitemuliert. Ansonsten merkt das Programm selber davon nichts. Auf nem realen Amiga verhält es sich deshalb logischerweise etwas anders... Jetzt werd ich mal Dein Programm ausprobieren. mfg -- Good coders do not comment. What was hard to write should be hard to read too. [ - Answer - Quote - Direct link - ] |
2006-09-17, 13:38 h whose Posts: 2156 User |
Zitat: Wie meinst Du das mit der Echtzeit-Uhr? GetSysTime() bzw. GETSYSTIME läuft ja im Grunde nur via EClock, die wird ja beim Start einmal auf den "aktuellen Stand" gebracht und läuft dann "allein" weiter, da tut sich zwischen Emulator und Amiga nicht viel (sofern der Emulator nicht an entscheidenden Stellen gebremst wird, was mir aber der Fall zu sein scheint. Manchmal weichen die Ergebnisse auf WinUAE wesentlich stärker ab als auf einem echten Amiga). Abweichungen der GetSysTime()-Zeit wirst Du trotzdem bemerken, aber aufgrund der seltsam glatten Zahlen glaube ich, daß diese Abweichungen vom GetSysTime()-"Overhead" stammen (meine Vermutung geht eher da hin, daß GetSysTime() auf den nächste VBlank wartet, bevor der Zähler das nächste Mal ausgelesen wird). Die Abweichungen treten übrigens stärker auf, je kleiner die Differenz wird (ich tippe auf zu hohe Last beim timer.device, so daß die GetSysTime()-Anfrage etwas zu spät "angenommen" wird). Es gibt aber einen Punkt, wo Du bei keinem Versuch mehr das "korrekte" Ergebnis bekommst, das ist der Punkt, wo die Systemzeit "abhaut" (bei mir inzwischen um die 12000Hz). Ab und an scheint sich da auch noch was anderes bemerkbar zu machen, weil hin und wieder weniger Zeit angezeigt wird (im Rahmen bis -20000µs, ich tippe da auf einen Kontext-Switch zur unpassenden Zeit). Bei geringeren Frequenzen überwiegt die Anzahl der "Treffer" bei weitem, aber auch dort kann man hin und wieder diese Abweichungen bei GetSysTime()beobachten. Zu doof, daß ich keinen Sampler habe, sonst hätte ich das schon etwas genauer ausloten können, ob diese Abweichungen tatsächlich aus der Richtung stammen, wo ich sie vermute. Man kann natürlich auch mal schauen, was die EClock dazu sagt (also die EClock-Unit als Referenz verwendet statt mit GetSysTime() zu messen). Ach nochwas: Mein Überlauf-Test ist ja wirklich etwas sehr einfach... hast Du da evtl. was Passendes auf Lager, was man an der Stelle einsetzen könnte? Ich hatte nie viel mit 64Bit-Zahlen zu tun (wenn man mal von Fließkommazahlen absieht), daher keine großen Kenntnisse zu dem Thema. Ein neckischer Trick, um auch mit vorzeichenbehafteten Zahlen korrekt umzugehen wäre etwas (auch wenn sowas in unserem Fall eher weniger von Verwendung ist, aber gebrauchen kann man sowas immer mal, denke ich) Grüße -- --- µA1 PPC 750GX-800 A4000 PPC 604e-233 [ Dieser Beitrag wurde von whose am 17.09.2006 um 13:52 Uhr geändert. ] [ - Answer - Quote - Direct link - ] |
2006-09-17, 21:33 h Holger Posts: 8116 User |
Zitat:Nun, dass mein Programm mit der EClock synchron ist, habe ich ja schon geschrieben. Deshalb habe ich auch keinen weiteren Test durchgeführt, der auf der EClock basiert. Bringt ja nix. Ich habe mit Date vor und nach dem Programm die reale Differenz gemessen, was man bei längeren Laufzeiten durchaus machen kann. Und da spielt's halt ne Rolle, ob man ne Echtzeituhr simuliert oder nicht, zumindest, solange die emulierte EClock von der Echtzeit erheblich abweicht. Zitat:Das habe ich bisher noch nicht bemerkt. Zitat:Wozu? ReadEClock() liefert doch schon die aktuelle EClock. So habe ich ja auch bei meinem Programm verifiziert, dass nach "WaitUntil x" die EClock auch "x + minimale Differenz" (aufgrund der nachträglichen Abfrage) enthält. Also kann ich Dir schon mal sagen, dass die EClock den erwarteten Wert enthält. Aber Du kannst ja nach dem Programm einfach noch mal ReadEClock() aufrufen... Zitat:Eigentlich habe ich in meinem Programm 64Bit-Arithmetik benutzt, um genau darüber nicht nachdenken zu müssen. mfg -- Good coders do not comment. What was hard to write should be hard to read too. [ - Answer - Quote - Direct link - ] |
2006-09-17, 21:59 h Holger Posts: 8116 User |
Zitat:An sich kein Wunder, wenn man sich Dein Programm ansieht. Du holst Dir die EClock, welche die Basis für Dein Warten ist, dann machst Du diverse Dinge, wie Textausgabe, Berechnungen und ersten Request verschicken, und dann erst holst Du die Systemzeit, die den Beginn der Aktion markieren soll, Deine EClock, die Du als Basis für WAIT_ECLOCK benutzt, liegt aber schon deutlich früher. Nur scheinen das Multitasking oder die Eigenheiten von GetSysTime() meistens noch größere Verfälschungen zu produzieren. Die Abrundung der Wartezeit (diff = ticks / intervall;) fällt da kaum noch in's Gewicht (verkleinert aber auch...). mfg Übrigens ist die while((TimerMsg = GetMsg(TimerMP))) Schleife ("Für den Fall, das unser Programm zu langsam sein sollte") sinnlos. Du verschickst zwischen den WaitPort-Aufrufen nur genau einmal einen Request, und das ist auch gut so, denn Du hast ja auch nur den einen. Wenn mehr als eine Message an dem Port ankommen würde, wäre das ziemlich mystisch. Ich versteh nicht, warum Du da nicht einfach WaitIO() benutzt. mfg -- Good coders do not comment. What was hard to write should be hard to read too. [ - Answer - Quote - Direct link - ] |
2006-09-17, 22:06 h whose Posts: 2156 User |
Zitat: Ah, ok. Nu hab ichs Zitat:Zitat:Das habe ich bisher noch nicht bemerkt. Evtl. hängts auch mit dem UAE zusammen... auf dem 4000er hatte ich das auch noch nicht, auf dem µA1 aber schon (allerdings 68K per JIT). Zitat:Zitat:Wozu? Naja, wenn Du das schon gemacht hast, brauche ich das ja nicht mehr. Ich darf also davon ausgehen, daß das jetzt paßt mit dem Timer? Zitat:Zitat:Eigentlich habe ich in meinem Programm 64Bit-Arithmetik benutzt, um genau darüber nicht nachdenken zu müssen. Och mööönsch Gibts da evtl. einen Link zu dem Thema, den Du posten könntest? Ich hab da mal nach gesucht, aber was wirklich brauchbares mit lesbarem Code habe ich dazu nicht gefunden. Alles mögliche, sogar 128Bit-Operationen, aber nichts über "simple" 64Bit-Operationen. Ok, mit den "Hauruck"-Operationen in meinem Programm kann man sich wohl behelfen, aber ich könnte mir gut vorstellen, daß es da noch wesentlich elegantere Methoden gibt? Grüße -- --- µA1 PPC 750GX-800 A4000 PPC 604e-233 [ - Answer - Quote - Direct link - ] |
2006-09-17, 22:07 h NoImag Posts: 1050 User |
Zitat: Es könnte auch daran liegen, dass die RKRM-Beipiele 1.x-kompatibel gehalten sind. Bei mir kann es deshalb vorkommen, dass ich vergesse das umzuschreiben, wenn ich mich dort bediene (was gerade bei Beispielen vorkommt). Tschüß [ - Answer - Quote - Direct link - ] |
First 3 4 5 6 7 -8- 9 10 11 | [ - Post reply - ] |
amiga-news.de Forum > Programmierung > Tonerkennung | [ - Search - New posts - Register - Login - ] |
Masthead |
Privacy policy |
Netiquette |
Advertising |
Contact
Copyright © 1998-2024 by amiga-news.de - all rights reserved. |