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 - ]

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

07.09.2006, 10:34 Uhr

Mad_Dog
Posts: 1944
Nutzer
Wie versprochen, hier das ganze mit improvisiertem Osziloskop.
Das Zeitfenster, welches betrachtet wird, ist 0,05 Sekunden.

Die Kanaltrennung (Stereo links/rechts) ist erraten:
c code:
l = Buffer[i] << 1 & 0xFF;
      r = Buffer[i] << 2 & 0xFF;

      WritePixel(rp,i,l+64);
      WritePixel(rp,i,r+128);


...und mit Sicherheit falsch.

...aber immerhin zucken jetzt zwei Kurven im Fenster, die so ähnlich wie ein Audiosignal aussehen. ;)

Die Header Datei:
c code:
/*  parallel.h
 +
 *  Makros für Low-Level Zugriff auf CIA
 *
 */

#ifndef PARALLEL_H
#define PARALLEL_H

#include <string.h>

// Adresse des Datenregisters für Parallelport
#define PARALLEL_PORT 0xBFE101

// Adresse des Registers für die Richtung des Parallelports
#define PARALLEL_DIR 0xBFE301

// Den Parallelport in den Lesemodus versetzen
#define SET_PARALLEL_PORT_READ (memset((void *)PARALLEL_DIR,0x0,1))

// Ein Byte vom Parallelport lesen
#define READ_PAR(x) (memmove((&x),(void *)PARALLEL_PORT,1))

#endif


Das eigentliche Programm (und ja: war auch ein Nacht- und Nebel Hack). ;)
c code:
/*  Oszi.c
 *  Osziloskop mit LowLevel Zugriff auf CIA
 *  Liest Daten von einem Parallelportsampler
 *  und gibt sie in einem Intuition-Fenster aus.
 *  Autor: Norman Walter
 *  Datum: 6.9.2006
 */

#include <stdio.h>
#include <stdlib.h>

#include <exec/types.h>
#include <exec/exec.h>
#include <exec/memory.h>
#include <exec/io.h>
#include <intuition/intuition.h>
#include <graphics/gfx.h>
#include <dos/dos.h>

#include <devices/timer.h>

#include <proto/intuition.h>
#include <proto/graphics.h>
#include <proto/exec.h>

#include <clib/alib_protos.h>
#include <clib/dos_protos.h>

#include "parallel.h"

// Samplingfrequenz (hier 8kHz)
#define SAMPLINGFREQ 8000

// Größe des Zeitfensters: Zeit in Sekunden
#define TIME 0.05

//  Wie groß soll das Zeitfenster sein, das wir betrachten?
#define FRAMESIZE SAMPLINGFREQ * TIME

// Puffer für das Sample
BYTE Buffer[FRAMESIZE];

#define WIDTH 400   // Breite des Fensters
#define HEIGHT 256  // Höhe des Fensters

struct Window *Fenster;               // Zeiger auf Window-Struktur
struct IntuitionBase *IntuitionBase;  // Zeiger auf IntuitionBase-Struktur
struct GfxBase *GfxBase;              // Zeiger auf GfxBase-Struktur

LONG black,green;  // Variablen für die Pen Nummern

struct timerequest *TimerIO = NULL;
struct MsgPort *TimerMP = NULL;
BYTE TimerDevice;

// Resourcen freigeben
void ShutDown(void)
{
    if (TimerMP) DeleteMsgPort(TimerMP);
    if (TimerIO) DeleteIORequest((struct IORequest *)TimerIO);
    if (TimerDevice) CloseDevice((struct IORequest *) TimerIO);
    if (Fenster) CloseWindow(Fenster);
    if (GfxBase) CloseLibrary((struct Library *) GfxBase);
    if (IntuitionBase) CloseLibrary((struct Library *) IntuitionBase);
}

void ReadFrame(void)
{
   int i;

   /*  Hier werden die Werte gesammelt
    *  Bei einer Samplingfrequenz von 8kHz
    *  und 8000 Werten sollte das genau
    *  eine Sekunde dauern
    */
   for (i=0;i<FRAMESIZE;i++)
   {
      WaitPort(TimerMP);

      if(1UL << TimerMP->mp_SigBit)
      {
          WaitIO((struct IORequest *)TimerIO);

          // Wert vom Parallelport kopieren
          READ_PAR(Buffer[i]);
          SendIO((struct IORequest *)TimerIO);
      }
   }
}

void ZeichneOsziloskop(struct Window *Win)
{
   int i;
   struct RastPort *rp;
   BYTE l,r;

   rp = Win->RPort;

   SetRast(rp,black);
   SetAPen(rp,green);

   for (i=0;i<FRAMESIZE;i++)
   {
      l = Buffer[i] << 1 & 0xFF;
      r = Buffer[i] << 2 & 0xFF;

      WritePixel(rp,i,l+64);
      WritePixel(rp,i,r+128);
   }
}

int main(void)
{
   /* Variablen zur Message-Bearbeitung */
   struct MsgPort *Port;             // Zeiger auf Message Port Struktur
   struct IntuiMessage *Nachricht;   // Zeiger auf Intuition Message Struktur
   ULONG  klasse;
   USHORT code;

   BOOL Ende=FALSE;

   TimerMP = CreateMsgPort();
   if (TimerMP == NULL) ShutDown();

   TimerIO = (struct timerequest *) CreateIORequest(TimerMP,sizeof(struct timerequest));
   if (TimerIO == NULL) ShutDown();

   /*  Wichtig: Für diesen Zweck brauchen wir UNIT_MICROHZ.
    *  Die anderen Timer sind zu ungenau, weil wir tatsächlich
    *  0,000125 Sekunden messen wollen, also 125 Mikroherz.
    */
   TimerDevice = OpenDevice(TIMERNAME,UNIT_MICROHZ,(struct IORequest *)TimerIO,0L);
   if (TimerDevice !=0) ShutDown();

   // Intuition Library öffnen
   IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library",36L);
   if (IntuitionBase == NULL) ShutDown();

   GfxBase = (struct GfxBase *) OpenLibrary("graphics.library",0L);
   if (GfxBase == NULL) ShutDown();

   // Fenster mittels Tags öffnen
   Fenster = OpenWindowTags(NULL,
                            WA_Left, 100,    // Abstand vom linken Rand
                            WA_Top, 100,     // Abstand vom oberen Rand
                            WA_Width, WIDTH,    // Breite
                            WA_Height, HEIGHT,  // Höhe
                            WA_Title, "Osziloskop",         // Fenstertitel
                            WA_CloseGadget, TRUE,           // Close-Gadget
                            WA_DragBar, TRUE,               // Ziehleiste
                            WA_DepthGadget, TRUE,           // Depth-Gadget
                            WA_GimmeZeroZero, TRUE,         // Ursprung 0/0
                            WA_IDCMP,
                            IDCMP_CLOSEWINDOW | IDCMP_INTUITICKS,
                            WA_Activate, TRUE,              // Fenster aktivieren
                            TAG_DONE);

   if (Fenster==NULL) ShutDown();

   Port=Fenster->UserPort;

   /* Pens ermitteln: Schwarz und Grün */
   black = ObtainBestPen(Fenster->WScreen->ViewPort.ColorMap,
                         0x00000000,0x00000000,0x00000000,
                         OBP_Precision,PRECISION_GUI,
                         TAG_DONE);

   green = ObtainBestPen(Fenster->WScreen->ViewPort.ColorMap,
                         0x00000000,0xFFFFFFFF,0x00000000,
                         OBP_Precision,PRECISION_GUI,
                         TAG_DONE);

   /* Issue the command and wait for it to finish, then get the reply */
   TimerIO->tr_node.io_Command = TR_GETSYSTIME;
   SendIO((struct IORequest *) TimerIO);

   // Den Parallelport in den Lesemodus versetzen
   SET_PARALLEL_PORT_READ;

   /*  Zyklischen Alarm setzen:
    *  1/SAMPLINGFREQ entspricht dabei einer Periode.
    *  Nach der Formel T = 1/n
    *  wobei n unsere Samplingfrequenz ist.
    *  (siehe auch jede beliebige Physik-Formelsammlung)
    */
   TimerIO->tr_node.io_Command = TR_ADDREQUEST;
   TimerIO->tr_time.tv_secs = 0;
   TimerIO->tr_time.tv_micro = 1/SAMPLINGFREQ;

   while (!Ende)
   {
      // Lese Zeitfenster
      ReadFrame();

      WaitPort(Port);

     /* Schleife läuft bis alle Ereignisse
      * abgearbeitet sind.
      */
      while(Nachricht=(struct IntuiMessage *)GetMsg(Port))
      {

        klasse = Nachricht->Class;
        code =  Nachricht->Code;

        /* Welches Ereignis ist eingetreten? */
        switch(klasse)
        {
          /* Close Gadget wurde angeklickt */
           case CLOSEWINDOW :
                Ende = TRUE; // Programmende
           break;

          /* Intuition hat sich gemeldet */
          case INTUITICKS :
               // Zeichne das Osziloskop
               ZeichneOsziloskop(Fenster);
          break;

        } // Ende der switch-Verzweigung

       /* Wir sind mit der Bearbeitung fertig
        * und beantworten die Nachricht.
        */
       ReplyMsg((struct Message *)Nachricht);
     }
   }

   AbortIO((struct IORequest *)TimerIO);
   WaitIO((struct IORequest *)TimerIO);

   // Die Pens wieder freigeben
   ReleasePen(Fenster->WScreen->ViewPort.ColorMap,black);
   ReleasePen(Fenster->WScreen->ViewPort.ColorMap,green);

   ShutDown();

   return 0;
}

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


[ Dieser Beitrag wurde von Mad_Dog am 07.09.2006 um 10:47 Uhr geändert. ]

[ - Antworten - Zitieren - Direktlink - ]

07.09.2006, 10:40 Uhr

Mad_Dog
Posts: 1944
Nutzer
Und hier noch ein Screenshot:

Bild: http://w3.norman-interactive.com/files/Oszi_1.png
--
http://www.norman-interactive.com

[ Dieser Beitrag wurde von Mad_Dog am 07.09.2006 um 10:41 Uhr geändert. ]

[ - Antworten - Zitieren - Direktlink - ]

07.09.2006, 10:45 Uhr

Mad_Dog
Posts: 1944
Nutzer
Zitat:
Original von Holger:
C code:
...
TimerIO->tr_time.tv_micro = 1/SAMPLINGFREQ;
...


Wos? 1/8000 ist 0, bei int-Werten.
War wohl schon ziemlich spät, ...aber so funktioniert das Programm eher aus Versehen...


Au weia! Du hast natürlich Recht. Und ja - es war spät.
In meim Oszi-Programm ist der selbe Fehler drin. :glow:


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

[ - Antworten - Zitieren - Direktlink - ]

07.09.2006, 12:03 Uhr

Holger
Posts: 8116
Nutzer
Zitat:
Original von MaikG:
Ich hab einen Fehler gefunden:

POKEW tr& + IORequestio_Command%, TR_ADDREQUEST&

muss heissen:

POKEW tr& + tr_node% + IORequestio_Command%, TR_ADDREQUEST&

dadurch wird es trotzdem mit der unterfunktion nicht schneller.
Mit init_wait direkt im Programm erreicht es fast Echtzeit.


Das hätte mich auch gewundert, wenn das einen Unterschied macht. tr_node% ist 0 (in Worten: null). Und weil es von der Logik her an der Stelle keinen Sinn macht, habe ich es weggelassen. io_Command ist direkter Member der IORequest-Struktur.

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

[ - Antworten - Zitieren - Direktlink - ]

07.09.2006, 12:13 Uhr

Holger
Posts: 8116
Nutzer
Zitat:
Original von Mad_Dog:
Die Kanaltrennung (Stereo links/rechts) ist erraten:
c code:
l = Buffer[i] << 1 & 0xFF;
r = Buffer[i] << 2 & 0xFF;


...und mit Sicherheit falsch.

Das ist gar nicht die Frage, die Frage ist eher, was dieser code überhaupt bezwecken soll. Und die andere Frage ist, wieso Du überhaupt glaubst, dass sich Dein sampler im Stereomodus befindet, wenn Du keinerlei Ahnung hast, wie man ihn in diesem Modus abfragt, anders gesagt, wie Du diesen Modus überhaupt einschaltest.

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

[ - Antworten - Zitieren - Direktlink - ]

07.09.2006, 13:07 Uhr

Mad_Dog
Posts: 1944
Nutzer
Zitat:
Original von Holger:
Zitat:
Original von Mad_Dog:
Die Kanaltrennung (Stereo links/rechts) ist erraten:
c code:
l = Buffer[i] << 1 & 0xFF;
r = Buffer[i] << 2 & 0xFF;


...und mit Sicherheit falsch.

Das ist gar nicht die Frage, die Frage ist eher, was dieser code überhaupt bezwecken soll. Und die andere Frage ist, wieso Du überhaupt glaubst, dass sich Dein sampler im Stereomodus befindet, wenn Du keinerlei Ahnung hast, wie man ihn in diesem Modus abfragt, anders gesagt, wie Du diesen Modus überhaupt einschaltest.

Zur Erklärung, warum "ich glaube, daß sich mein Sampler im Stereomodus befindet" Folgendes: Ich hab zuerst einfach die Werte aus dem Array Buffer[] als Linien ausgegeben: Angefangen von x=t (bzw. hier i), also dem Zeitpunkt und y=Buffer[i]+128 (also die Amplitude) mit +128 für die Koordinatentransformation wegen der Nullinie. Ergebnis: Es sah so aus, als ob hier das Audiosignal vom Rechten und Linken Kanal gleichzeitig ankommt. O.k. Du hast jetzt keinen solchen Sampler parat, aber wenn Du's sehen würdest, würdest Du verstehen, was ich meine. Also muß es irgendeine Möglichkeit geben, diesen rechts/links Mix auseinanderzufriemeln. Leider hab ich auch keine Ahnung wie das geht. Ich nehme mal nicht an, daß es im Stereo Modus nur 4 Bit pro Kanal sind.

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

[ - Antworten - Zitieren - Direktlink - ]

07.09.2006, 13:35 Uhr

Holger
Posts: 8116
Nutzer
@Mad_Dog:
Du scheinst immer noch nicht akzeptieren zu wollen, dass der Wert unsigned sein könnte.

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

[ - Antworten - Zitieren - Direktlink - ]

07.09.2006, 13:48 Uhr

Mad_Dog
Posts: 1944
Nutzer
Zitat:
Original von Holger:
@Mad_Dog:
Du scheinst immer noch nicht akzeptieren zu wollen, dass der Wert unsigned sein könnte.


Ja, könnte. Wenn dem so wäre, dann könnte es tatsächlich sein, dass der Wert für den linken/Rechten Kanal jeweils als Halbbyte vorliegt - z.B. mit einem Wertebereich von jeweils 0-127.
Vielleicht komm ich heute abend dazu, weiter zu experimentieren.

Übrigens: Der "murks-Trenncode" entstand auch so. Hab die Halbbytes gelesen und weil kein 'gscheites Ergebnis rauskam, hab ich eben spaßeshalber die Bits ein wenig rumgeschoben. Ist natürlich quatsch, aber zumindest die obere Kurve sieht halbwegs brauchbar aus.

Solange keiner ne Doku hat, bleibt nur Reverse Engineering. ;)

Noch was: Für AHI gibt's auch ein parallelport-Sampler Treiber. Das Programm "Advanced AHI Recorder" funktioniert auch (in Stereo) mit meinem "Stereo Master" und vermutlich mit vielen anderen Samplern auch. Also muß es doch einen gewissen gemeinsamen Nenner geben.

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


[ Dieser Beitrag wurde von Mad_Dog am 07.09.2006 um 13:51 Uhr geändert. ]

[ - Antworten - Zitieren - Direktlink - ]

07.09.2006, 15:22 Uhr

Mad_Dog
Posts: 1944
Nutzer
Zitat:
Original von MaikG:

Das wird wohl durch irgendeinen Pin umgeschalten. Aufmodulieren,
mh, wie soll ich das erklären. Beim Kabelfernsehn hast du auch
mehrere Sender, das das geht ist so weil die auf verschiedenen
Frequenzen liegen. Und beim Sampler ist das genauso der eine Kanal
ist ganz normal, der andere beginnt ab ca. 20kHz.


Verwechselst Du nicht Aufmodulieren und Multiplexen?
Am Parallelport kommt ein digitales Signal an, d.h. irgendwelche der 8 Pins sind "heiß". Die ergeben dann zusammen einen 8 Bit Wert. Die einzige Frequenz, die es da noch gibt, ist die Frequenz mit der ich den Port abfrage (also wie oft pro Sekunde). Ich sehe nicht, wo man da was aufmodulieren soll.

Falls Du eine Ahnung hast, wie man aus dem einen 8 Bit Wert pro Zeiteinheit den linken/rechten Kanal herausbekommt, dann her damit! :)
--
http://www.norman-interactive.com

[ - Antworten - Zitieren - Direktlink - ]

07.09.2006, 15:28 Uhr

MaikG
Posts: 5172
Nutzer
>Das hätte mich auch gewundert, wenn das einen Unterschied macht.
>tr_node% ist 0 (in Worten: null). Und weil es von der Logik her an
>der Stelle keinen Sinn macht, habe ich es weggelassen. io_Command
>ist direkter Member der IORequest-Struktur.

Schade, da dachte ich ich hätte einen Fehler gefunden...

Also der Stereomodus wird wohl über Pin12/Paper Out gesteuert.
Dieser Pin geht an den 4066, das ist der Stereo-Encoder.
Ich denke, da ich nur auf einem Chincheingang ein Signal bekomme,
ich mich im "Mono"-Modus befinde.

[ - Antworten - Zitieren - Direktlink - ]

07.09.2006, 15:50 Uhr

Mad_Dog
Posts: 1944
Nutzer
Zitat:
Original von MaikG:
Also der Stereomodus wird wohl über Pin12/Paper Out gesteuert.
Dieser Pin geht an den 4066, das ist der Stereo-Encoder.
Ich denke, da ich nur auf einem Chincheingang ein Signal bekomme,
ich mich im "Mono"-Modus befinde.


Aber wie trennst Du in Deinem Programm die Kanäle?
--
http://www.norman-interactive.com

[ - Antworten - Zitieren - Direktlink - ]

07.09.2006, 16:05 Uhr

Holger
Posts: 8116
Nutzer
Zitat:
Original von Mad_Dog:
Ja, könnte. Wenn dem so wäre, dann könnte es tatsächlich sein, dass der Wert für den linken/Rechten Kanal jeweils als Halbbyte vorliegt - z.B. mit einem Wertebereich von jeweils 0-127.
Vielleicht komm ich heute abend dazu, weiter zu experimentieren.


Kleiner Tip: Lass es.
Wenn Du nicht bereit bist, einfach mal das als gegeben anzunehmen, was ein anderer schon vorher geschrieben hat, kannst Du noch Jahre ohne sinnvolles Ergebnis rumspielen.

Wenn MaikG schreibt, dass es ein unsigned byte ist, dann wäre es doch wohl das Mindeste, genau das einmal auszuprobieren, bevor man anfängt, wild irgendwie bitweise zu verschieben. Übrigens werden aus 8 Bit keine 16, egal wie Du sie hin- und herschiebst.

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

[ - Antworten - Zitieren - Direktlink - ]

07.09.2006, 18:02 Uhr

MaikG
Posts: 5172
Nutzer
>Aber wie trennst Du in Deinem Programm die Kanäle?

Muss man gar nicht, weil da ja nur einer ankommt. Weil
default ist Linker Kanal und nur dieser.

[ - Antworten - Zitieren - Direktlink - ]

08.09.2006, 10:27 Uhr

Mad_Dog
Posts: 1944
Nutzer
Na gut, dann bleiben wir eben vorerst bei Mono.

Ich präsentiere Euch das "Monoscope" :

Bild: http://w3.norman-interactive.com/files/Monoscope.png

Sieht doch schonmal ganz gut aus, oder? :)

Im Vergleich zum vorherigen Code hat sich nicht viel geändert. Und ja - es scheint ein unsigned Byte zu sein. Gleichzeitig habe ich noch die Samplingfrequenz auf 32kHz hochgesetzt und dafür das Zeitfenster kleiner gemacht.
c code:
/*  Monoscope.c
 *  Osziloskop mit LowLevel Zugriff auf CIA
 *  Liest Daten von einem Parallelportsampler (Mono)
 *  und gibt sie in einem Intuition-Fenster aus.
 *  Autor: Norman Walter
 *  Datum: 7.9.2006
 */

#include <stdio.h>
#include <stdlib.h>

#include <exec/types.h>
#include <exec/exec.h>
#include <exec/memory.h>
#include <exec/io.h>
#include <intuition/intuition.h>
#include <graphics/gfx.h>
#include <dos/dos.h>

#include <devices/timer.h>

#include <proto/intuition.h>
#include <proto/graphics.h>
#include <proto/exec.h>

#include <clib/alib_protos.h>
#include <clib/dos_protos.h>

#include "parallel.h"

// Samplingfrequenz (hier 32kHz)
#define SAMPLINGFREQ 32000

// Größe des Zeitfensters: Zeit in Sekunden
#define TIME 0.0125

//  Wie groß soll das Zeitfenster sein, das wir betrachten?
#define FRAMESIZE SAMPLINGFREQ * TIME

// Periode in Mikrosekunden
#define PERIODE (int)1E6/SAMPLINGFREQ

// Puffer für das Sample
UBYTE Buffer[FRAMESIZE];

#define WIDTH 400   // Breite des Fensters
#define HEIGHT 256  // Höhe des Fensters

struct Window *Fenster;               // Zeiger auf Window-Struktur
struct IntuitionBase *IntuitionBase;  // Zeiger auf IntuitionBase-Struktur
struct GfxBase *GfxBase;              // Zeiger auf GfxBase-Struktur

LONG black,green;  // Variablen für die Pen Nummern

struct timerequest *TimerIO = NULL;
struct MsgPort *TimerMP = NULL;
UBYTE TimerDevice;

// Resourcen freigeben
void ShutDown(void)
{
    if (TimerMP) DeleteMsgPort(TimerMP);
    if (TimerIO) DeleteIORequest((struct IORequest *)TimerIO);
    if (TimerDevice) CloseDevice((struct IORequest *) TimerIO);
    if (Fenster) CloseWindow(Fenster);
    if (GfxBase) CloseLibrary((struct Library *) GfxBase);
    if (IntuitionBase) CloseLibrary((struct Library *) IntuitionBase);
}

void ReadFrame(void)
{
   int i;

   /*  Hier werden die Werte gesammelt
    */
   for (i=0;i<FRAMESIZE;i++)
   {
      WaitPort(TimerMP);

      if(1UL << TimerMP->mp_SigBit)
      {
          WaitIO((struct IORequest *)TimerIO);

          // Wert vom Parallelport kopieren
          READ_PAR(Buffer[i]);
          SendIO((struct IORequest *)TimerIO);
      }
   }
}

void ZeichneOsziloskop(struct Window *Win)
{
   int t;
   struct RastPort *rp;

   rp = Win->RPort;

   SetRast(rp,black);
   SetAPen(rp,green);

   for (t=0;t<FRAMESIZE;t++)
   {
      Move(rp,t,Win->Height/2);
      Draw(rp,t,Buffer[t]);
   }
}

int main(void)
{
   /* Variablen zur Message-Bearbeitung */
   struct MsgPort *Port;             // Zeiger auf Message Port Struktur
   struct IntuiMessage *Nachricht;   // Zeiger auf Intuition Message Struktur
   ULONG  klasse;
   USHORT code;

   BOOL Ende=FALSE;

   TimerMP = CreateMsgPort();
   if (TimerMP == NULL) ShutDown();

   TimerIO = (struct timerequest *) CreateIORequest(TimerMP,sizeof(struct timerequest));
   if (TimerIO == NULL) ShutDown();

   /*  Wichtig: Für diesen Zweck brauchen wir UNIT_MICROHZ.
    *  Die anderen Timer sind zu ungenau.
    */
   TimerDevice = OpenDevice(TIMERNAME,UNIT_MICROHZ,(struct IORequest *)TimerIO,0L);
   if (TimerDevice !=0) ShutDown();

   // Intuition Library öffnen
   IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library",36L);
   if (IntuitionBase == NULL) ShutDown();

   GfxBase = (struct GfxBase *) OpenLibrary("graphics.library",0L);
   if (GfxBase == NULL) ShutDown();

   // Fenster mittels Tags öffnen
   Fenster = OpenWindowTags(NULL,
                            WA_Left, 100,    // Abstand vom linken Rand
                            WA_Top, 100,     // Abstand vom oberen Rand
                            WA_Width, WIDTH,    // Breite
                            WA_Height, HEIGHT,  // Höhe
                            WA_Title, "Monoscope",          // Fenstertitel
                            WA_ScreenTitle,"Monoscope V1.0 © 2006 by Norman Walter",
                            WA_CloseGadget, TRUE,           // Close-Gadget
                            WA_DragBar, TRUE,               // Ziehleiste
                            WA_DepthGadget, TRUE,           // Depth-Gadget
                            WA_GimmeZeroZero, TRUE,         // Ursprung 0/0
                            WA_IDCMP,
                            IDCMP_CLOSEWINDOW | IDCMP_INTUITICKS,
                            WA_Activate, TRUE,              // Fenster aktivieren
                            TAG_DONE);

   if (Fenster==NULL) ShutDown();

   Port=Fenster->UserPort;

   /* Pens ermitteln: Schwarz und Grün */
   black = ObtainBestPen(Fenster->WScreen->ViewPort.ColorMap,
                         0x00000000,0x00000000,0x00000000,
                         OBP_Precision,PRECISION_GUI,
                         TAG_DONE);

   green = ObtainBestPen(Fenster->WScreen->ViewPort.ColorMap,
                         0x00000000,0xFFFFFFFF,0x00000000,
                         OBP_Precision,PRECISION_GUI,
                         TAG_DONE);

   /* Issue the command and wait for it to finish, then get the reply */
   TimerIO->tr_node.io_Command = TR_GETSYSTIME;
   SendIO((struct IORequest *) TimerIO);

   // Den Parallelport in den Lesemodus versetzen
   SET_PARALLEL_PORT_READ;

   /*  Zyklischen Alarm setzen:
    *  1/SAMPLINGFREQ entspricht dabei einer Periode.
    *  Nach der Formel T = 1/n
    *  wobei n unsere Samplingfrequenz ist.
    *  (siehe auch jede beliebige Physik-Formelsammlung)
    */
   TimerIO->tr_node.io_Command = TR_ADDREQUEST;
   TimerIO->tr_time.tv_secs = 0;
   TimerIO->tr_time.tv_micro = PERIODE;

   while (!Ende)
   {
      // Lese Zeitfenster
      ReadFrame();

      WaitPort(Port);

     /* Schleife läuft bis alle Ereignisse
      * abgearbeitet sind.
      */
      while(Nachricht=(struct IntuiMessage *)GetMsg(Port))
      {

        klasse = Nachricht->Class;
        code =  Nachricht->Code;

        /* Welches Ereignis ist eingetreten? */
        switch(klasse)
        {
          /* Close Gadget wurde angeklickt */
           case CLOSEWINDOW :
                Ende = TRUE; // Programmende
           break;

          /* Intuition hat sich gemeldet */
          case INTUITICKS :
               // Zeichne das Osziloskop
               ZeichneOsziloskop(Fenster);
          break;

        } // Ende der switch-Verzweigung

       /* Wir sind mit der Bearbeitung fertig
        * und beantworten die Nachricht.
        */
       ReplyMsg((struct Message *)Nachricht);
     }
   }

   AbortIO((struct IORequest *)TimerIO);
   WaitIO((struct IORequest *)TimerIO);

   // Die Pens wieder freigeben
   ReleasePen(Fenster->WScreen->ViewPort.ColorMap,black);
   ReleasePen(Fenster->WScreen->ViewPort.ColorMap,green);

   ShutDown();

   return 0;
}


Was mich noch ein wenig stört: Das direkte Rumklopfen auf den CIA Registern. Es wäre schöner, wenn man das über das parallel.device machen könnte. Allerdings habe ich es bis jetzt noch nicht hinbekommen, mittels parallel.device ein Byte vom Parallelport zu lesen.
--
http://www.norman-interactive.com


[ Dieser Beitrag wurde von Mad_Dog am 08.09.2006 um 10:30 Uhr geändert. ]

[ - Antworten - Zitieren - Direktlink - ]

08.09.2006, 10:32 Uhr

Mad_Dog
Posts: 1944
Nutzer
Zitat:
Original von MaikG:
>Aber wie trennst Du in Deinem Programm die Kanäle?

Muss man gar nicht, weil da ja nur einer ankommt. Weil
default ist Linker Kanal und nur dieser.


O.k. Für Deinen Zweck reicht Mono aus. Aber mich würde es schon interessieren, wie man Stereo Sound bekommt. :)


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

[ Dieser Beitrag wurde von Mad_Dog am 08.09.2006 um 10:32 Uhr geändert. ]

[ - Antworten - Zitieren - Direktlink - ]

08.09.2006, 11:22 Uhr

Mad_Dog
Posts: 1944
Nutzer
@MaikG:

Könntest Du bei Gelegenheit mal ausprobieren, ob mein "Monoscope" auf Deimem Sampler läuft?
--
http://www.norman-interactive.com

[ Dieser Beitrag wurde von Mad_Dog am 08.09.2006 um 11:25 Uhr geändert. ]

[ - Antworten - Zitieren - Direktlink - ]

08.09.2006, 12:56 Uhr

Holger
Posts: 8116
Nutzer
@Mad_Dog:
Ich kann mit nicht vorstellen, dass das Timing bei Deinem Programm wirklich korrekt funktioniert. Das timer.device löscht die Zeitangabe in dem TimeRequest nach der Bearbeitung des TR_ADDREQUEST. Wenn Du also nur einmal am Anfang des Programms die Wartezeit in den Request schreibst, wartest Du nur genau einmal diese Zeit und ab dann 0s,0µs. Das verzögert zwar auch ein bisschen, dass dabei aber eine kontrollierbare Frequenz herauskommen soll, kann ich nicht glauben.

Übrigens habe ich bei meinem C-Programm, wenn man den TimeRequest korrekt vor jedem TR_ADDREQUEST mit der gewünschten Wartezeit befüllt, exakt die gleichen Resultate, wie mit dem Basic-Programm. Wenn man kleine Wartezeiten in den Regionen, wie hier benötigt, anfordert, beginnt der timer selbst falsch (meist zu langsam) zu laufen.

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

[ - Antworten - Zitieren - Direktlink - ]

08.09.2006, 13:22 Uhr

Mad_Dog
Posts: 1944
Nutzer
Zitat:
Original von Holger:
@Mad_Dog:
Ich kann mit nicht vorstellen, dass das Timing bei Deinem Programm wirklich korrekt funktioniert. Das timer.device löscht die Zeitangabe in dem TimeRequest nach der Bearbeitung des TR_ADDREQUEST.


Hab ich nicht gewußt. Danke für den Hinweis.





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

[ - Antworten - Zitieren - Direktlink - ]

08.09.2006, 15:11 Uhr

MaikG
Posts: 5172
Nutzer
>O.k. Für Deinen Zweck reicht Mono aus. Aber mich würde es schon
>interessieren, wie man Stereo Sound bekommt. :)


Hab ich dir doch erklärt, man schaltet Stereo ein und bekommt
dann bei einer Rate von 44khz 2x 22khz Samples. Du musst alles
was oberhalb von den ersten 22khz liegt auf 0-22khz bringen und
von den unteren 22khz Isolieren. Frag mich nicht wie das geht.
Ich hab aber im Aminet ein Sampler Schaltplan gesehen, der das
mit switching macht, da setzt man dann einen extra Pin, liesst
1 Byte Rechts, löscht den liesst dann 1 Byte Links. Also
Stereotechnisch scheint es unterschiedliche Versionen zu geben.

>Könntest Du bei Gelegenheit mal ausprobieren, ob mein "Monoscope"
>auf Deimem Sampler läuft?

Sicher, hast du das auch fertig Compiliert?

MaikG492 at directbox.com



>Übrigens habe ich bei meinem C-Programm, wenn man den TimeRequest
>korrekt vor jedem TR_ADDREQUEST mit der gewünschten Wartezeit
>befüllt, exakt die gleichen Resultate, wie mit dem Basic-Programm.
>Wenn man kleine Wartezeiten in den Regionen, wie hier benötigt,
>anfordert, beginnt der timer selbst falsch (meist zu langsam) zu
>laufen.

Dachte ich mir, was ist also falsch?
a) Die Funktion ist nicht für ein Loop gedacht?

oder

b) Funktion verkehrt aufgerufen?


Muss man das Timing vielleicht direkt über die CIA-Timer laufen lassen?

[ - Antworten - Zitieren - Direktlink - ]

08.09.2006, 15:48 Uhr

Mad_Dog
Posts: 1944
Nutzer
Zitat:
Original von MaikG:
Hab ich dir doch erklärt, man schaltet Stereo ein und bekommt
dann bei einer Rate von 44khz 2x 22khz Samples. Du musst alles
was oberhalb von den ersten 22khz liegt auf 0-22khz bringen und
von den unteren 22khz Isolieren. Frag mich nicht wie das geht.
Ich hab aber im Aminet ein Sampler Schaltplan gesehen, der das
mit switching macht, da setzt man dann einen extra Pin, liesst
1 Byte Rechts, löscht den liesst dann 1 Byte Links. Also
Stereotechnisch scheint es unterschiedliche Versionen zu geben.


O.k. damit kann ich was anfangen. Wenn man mit einem Bit wahlweise den rechten/linken Kanal auslesen kann, ist das ein Multiplexverfahren. Man nimmt einfach die doppelte Samplingfrequenz und liest immer abwechselnd den linken und rechten Kanal aus. So hat man dann jeweils 8 Bit für den linken und rechten Kanal.

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

[ - Antworten - Zitieren - Direktlink - ]

08.09.2006, 16:19 Uhr

Holger
Posts: 8116
Nutzer
Zitat:
Original von MaikG:
Dachte ich mir, was ist also falsch?
a) Die Funktion ist nicht für ein Loop gedacht?

Na ja, die Dokumentation sagt über den (8520) timer "It has precision down to about 2 microseconds, but will drift as system load increases." Ich hätte nur nicht gedacht, dass es so extrem wird.
Zitat:
oder
b) Funktion verkehrt aufgerufen?

Ich habe testweise auf UNIT_WAITUNTIL umgestellt und auf die vorberechnete Zeit (Programmstartzeitpunkt + n * 125µs) warten lassen. Dabei konnte man feststellen, dass es der timer selbst ist, dessen Geschwindigkeit bei kleinen Intervallen falsch läuft. Wenn Du also mittels GetSysTime vor und nach dem Programm die Zeit nimmst, stellst Du fest, dass die Differenz dem eigentlich gewünschten Wert entspricht. Nur die Realzeit weicht davon ab.
Zitat:
Muss man das Timing vielleicht direkt über die CIA-Timer laufen lassen?
Da sehe ich momentan keine Alternative. Die vom timer.device angebotenen Optionen sind offenbar unbrauchbar.

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

[ - Antworten - Zitieren - Direktlink - ]

08.09.2006, 16:35 Uhr

bubblebobble
Posts: 707
Nutzer
Hier mein Senf dazu:

ACHTUNG: GetSysTime hat möglicherweise eine niedrige Auflösung. Unter WinUAE wird dazu der 50Hz BLank verwendet, das reicht natürlich nicht.

Eine Möglichkeit zu timen wäre die eclock zu pollen. (ReadEClock)
Ansonsten sollte mit WAITECLOCK mit vorherberechnetem Zeitraster funktionieren. (so funktioniert der MID timer in HD-Rec).

Der CIA chip wird bei CPU Belastung bis zu 25% schneller.

--
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 - ]

08.09.2006, 18:01 Uhr

MaikG
Posts: 5172
Nutzer
>Ich habe testweise auf UNIT_WAITUNTIL umgestellt und auf die
>vorberechnete Zeit (Programmstartzeitpunkt + n * 125µs) warten
>lassen. Dabei konnte man feststellen, dass es der timer selbst ist,
>dessen Geschwindigkeit bei kleinen Intervallen falsch läuft. Wenn Du
>also mittels GetSysTime vor und nach dem Programm die Zeit nimmst,
>stellst Du fest, dass die Differenz dem eigentlich gewünschten Wert
>entspricht. Nur die Realzeit weicht davon ab.

Also das Komplette timer.device weicht ab, auch die Systemzeit???


> Zitat:
> Muss man das Timing vielleicht direkt über die CIA-Timer laufen lassen?

>Da sehe ich momentan keine Alternative. Die vom timer.device
>angebotenen Optionen sind offenbar unbrauchbar.

Keine alternative zum timer.device? Ich meine irgendwie Funktioniert
ja auch diverse Sample-Software.


>Eine Möglichkeit zu timen wäre die eclock zu pollen. (ReadEClock)
>Ansonsten sollte mit WAITECLOCK mit vorherberechnetem Zeitraster funktionieren. (so funktioniert der MID timer in HD-Rec).

Muss ich mal gucken ob ich dazu etwas finde.

>Der CIA chip wird bei CPU Belastung bis zu 25% schneller.

Taugt also auch nichts?


[ - Antworten - Zitieren - Direktlink - ]

08.09.2006, 18:19 Uhr

bubblebobble
Posts: 707
Nutzer
In meinen Inlcudes findest du Beispiel Code für die direkte Benutzung des CIA chips sowie das gleiche nochmal mit dem timer.device, der jeweils genau das macht was du bräuchtest.

Ist aber eben AB2.

--
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 - ]

08.09.2006, 18:37 Uhr

whose
Posts: 2156
Nutzer
125 µHz liefern die CIA-Timer relativ problemlos und selbst bei hoher Last ohne große Drift. Viele AHI-Treiber z.B. benutzen diese Timer. Ich vermute, daß irgendwo zu viel Zeit verplempert wird, bevor der Timer neu gestartet wird. Das muß sehr flott gehen, alles andere kann und muss warten.

Ich weiß auch nicht, ob es so sonderlich genial ist, ein WaitIO() vor den Neustart des Timers zu setzen (C-Variante). Das würde ich mal weglassen.

Im BASIC-Programm dürften die Textausgaben störend wirken, nun weiß ich nicht, wie viele davon schon zu Testzwecken weggelassen wurden, um das Ganze schneller zu kriegen. Da dürfte auf jeden Fall noch was zu holen sein.

Grüße



--
---

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


[ Dieser Beitrag wurde von whose am 08.09.2006 um 18:48 Uhr geändert. ]

[ - Antworten - Zitieren - Direktlink - ]

08.09.2006, 18:55 Uhr

bubblebobble
Posts: 707
Nutzer
Textausgaben darf der samplende Task natürlich nicht machen, dasist viel zu langsam. Er sollte besser überhaupt nichts machen ausser samplen, und sollte auch möglichst mit einer TaskPri >20 laufen.

--
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 - ]

08.09.2006, 22:19 Uhr

Holger
Posts: 8116
Nutzer
Zitat:
Original von whose:
125 µHz liefern die CIA-Timer relativ problemlos und selbst bei hoher Last ohne große Drift. Viele AHI-Treiber z.B. benutzen diese Timer. Ich vermute, daß irgendwo zu viel Zeit verplempert wird, bevor der Timer neu gestartet wird. Das muß sehr flott gehen, alles andere kann und muss warten.

Ich weiß auch nicht, ob es so sonderlich genial ist, ein WaitIO() vor den Neustart des Timers zu setzen (C-Variante). Das würde ich mal weglassen.

Man MUSS den gesendeten Request wieder abholen, bevor man ihn erneut versendet. Und jedesmal einen neuen Request anlegen, wäre genauso unsinnig, dann läuft der Speicher voll. Also auf die Antwort MUSS man warten, ob nun via WaitIO oder WaitPort/GetMsg ist gehupft wie gesprungen.

Und da ich in meinem C-Programm mittels WAIT_UNTIL auf die vorberechnete Zeit gewartet habe, kann es gar nicht am Verplempern der Zeit liegen, weil der Request ja sofort zurückkommen müsste, wenn der angegebene Zeitpunkt schon überschritten ist. Es seit denn, der timer selber ist langsamer geworden.

An dem Rest des Programms kanns ja nicht liegen, der rennt, wenn man den timer weglässt, in einem zehntel der Zeit durch...

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

[ - Antworten - Zitieren - Direktlink - ]

08.09.2006, 23:42 Uhr

MaikG
Posts: 5172
Nutzer
>In meinen Inlcudes findest du Beispiel Code für die direkte
>Benutzung des CIA chips sowie das gleiche nochmal mit dem
>timer.device, der jeweils genau das macht was du bräuchtest.

Das was ich schonmal runtergeladen habe?


>Ich vermute, daß irgendwo zu viel Zeit verplempert wird,
>bevor der Timer neu gestartet wird. Das muß sehr flott gehen,
>alles andere kann und muss warten.

Nee, ich kann zwischen SendIO und WaitIO alles rausnehmen, trotzdem
ist das saulahm und liefert keine korrekten werte.
125 wird nicht ganz erreicht, gebe ich z.B. 25 ein wird die
gleiche Zeit benötigt.

>Im BASIC-Programm dürften die Textausgaben störend wirken, nun weiß
>ich nicht, wie viele davon schon zu Testzwecken weggelassen wurden,
>um das Ganze schneller zu kriegen. Da dürfte auf jeden Fall noch
>was zu holen sein.

Ich habe die Textausgaben zu 100% weggelassen, das macht gar keinen
unterschied.


>Und da ich in meinem C-Programm mittels WAIT_UNTIL auf die
>vorberechnete Zeit gewartet habe, kann es gar nicht am Verplempern
>der Zeit liegen, weil der Request ja sofort zurückkommen müsste,
>wenn der angegebene Zeitpunkt schon überschritten ist. Es seit denn,
>der timer selber ist langsamer geworden.


WaitUntil ist wie MircoHZ, kein unterschied, allerdings verstehe
ich das mit der vorberechneten Zeit nicht.

[ - Antworten - Zitieren - Direktlink - ]

09.09.2006, 00:48 Uhr

whose
Posts: 2156
Nutzer
Zitat:
Original von Holger:
Zitat:
Original von whose:
125 µHz liefern die CIA-Timer relativ problemlos und selbst bei hoher Last ohne große Drift. Viele AHI-Treiber z.B. benutzen diese Timer. Ich vermute, daß irgendwo zu viel Zeit verplempert wird, bevor der Timer neu gestartet wird. Das muß sehr flott gehen, alles andere kann und muss warten.

Ich weiß auch nicht, ob es so sonderlich genial ist, ein WaitIO() vor den Neustart des Timers zu setzen (C-Variante). Das würde ich mal weglassen.

Man MUSS den gesendeten Request wieder abholen, bevor man ihn erneut versendet. Und jedesmal einen neuen Request anlegen, wäre genauso unsinnig, dann läuft der Speicher voll. Also auf die Antwort MUSS man warten, ob nun via WaitIO oder WaitPort/GetMsg ist gehupft wie gesprungen.

Mal abgesehen davon, daß in dem C-Beispiel ZWEIMAL "gewartet" wird. Einmal mittels WaitPort() auf den TimerMP, dann nochmal mittels WaitIO().

WaitPort()/GetMsg() tut seinen Dienst hervorragend und man kann den Request direkt wiederverwenden.

Zitat:
Und da ich in meinem C-Programm mittels WAIT_UNTIL auf die vorberechnete Zeit gewartet habe, kann es gar nicht am Verplempern der Zeit liegen, weil der Request ja sofort zurückkommen müsste, wenn der angegebene Zeitpunkt schon überschritten ist. Es seit denn, der timer selber ist langsamer geworden.

Jetzt würde mich mal interessieren, wie Du das "die Timer werden langsamer" gemessen hast. In vielen Fällen (hohe Systemlast) kann es sogar passieren, daß die Timer schneller werden...

Zitat:
An dem Rest des Programms kanns ja nicht liegen, der rennt, wenn man den timer weglässt, in einem zehntel der Zeit durch.

Ja und? Was heißt das? Ich weiß nur, daß die Timer recht genau laufen, auch bei sehr kleinen Zeitabschnitten. Die Drift wird erst dann sehr hoch, wenn ein anderer Task fast 100% der Systemzeit bekommt/frißt. Die Drift kann dabei in beide Richtungen laufen.

Wenns denn unbedingt sein muß, nutz doch mal die Zähler der CIA direkt. Irgendwo in den RKMs geistert ein Beispiel dafür rum, wie man das macht. Dann siehst Du ja, ob die Timer tatsächlich "langsamer" werden. Ich glaube da nicht so wirklich dran.

Grüße

--
---

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

[ - Antworten - Zitieren - Direktlink - ]

09.09.2006, 00:54 Uhr

whose
Posts: 2156
Nutzer
Zitat:
Original von MaikG:

>Ich vermute, daß irgendwo zu viel Zeit verplempert wird,
>bevor der Timer neu gestartet wird. Das muß sehr flott gehen,
>alles andere kann und muss warten.

Nee, ich kann zwischen SendIO und WaitIO alles rausnehmen, trotzdem
ist das saulahm und liefert keine korrekten werte.
125 wird nicht ganz erreicht, gebe ich z.B. 25 ein wird die
gleiche Zeit benötigt.


Das ist schon recht merkwürdig. Den Goertzel hast Du auch rausgenommen und die Werte in ein Array schreiben lassen? Wenn ja, und die Timer sind auch raus, verbockt MB da irgendwas.

Zitat:
>Im BASIC-Programm dürften die Textausgaben störend wirken, nun weiß
>ich nicht, wie viele davon schon zu Testzwecken weggelassen wurden,
>um das Ganze schneller zu kriegen. Da dürfte auf jeden Fall noch
>was zu holen sein.

Ich habe die Textausgaben zu 100% weggelassen, das macht gar keinen
unterschied.


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

Zitat:
>Und da ich in meinem C-Programm mittels WAIT_UNTIL auf die
>vorberechnete Zeit gewartet habe, kann es gar nicht am Verplempern
>der Zeit liegen, weil der Request ja sofort zurückkommen müsste,
>wenn der angegebene Zeitpunkt schon überschritten ist. Es seit denn,
>der timer selber ist langsamer geworden.

WaitUntil ist wie MircoHZ, kein unterschied, allerdings verstehe
ich das mit der vorberechneten Zeit nicht.


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

Grüße

--
---

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

[ - Antworten - Zitieren - Direktlink - ]


1 2 3 4 -5- 6 7 8 9 10 Letzte [ - 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.
.