Copyright (c) Hyperion Entertainment and contributors.

Programming AmigaOS 4: Datatypes - Making Life Easy

From AmigaOS Documentation Wiki
Jump to navigation Jump to search

This article was adapted from Amiga Future magazine's series on developing for AmigaOS....

Although the Datatypes haven't really been changed or reworked in AmigaOS 4, they should however still be he given some attention in the context of this workshop, because they can make the life of the programmer significantly easier.

Datatypes are an ingenious concept, unlike anything found on other platforms in this form. The specific program requires a file of a certain datatype (such as; images, sound, text) and the operating system automatically takes care of changing the format to the required one on the harddrive, at least when there is an interpreter available.

The main groups that exist are:

GID_SYSTEM (syst) System-Files
GID_TEXT (text) ASCII-Text
GID_DOCUMENT (docu) Document (Text and Graphics)
GID_SOUND (soun) Sound/Sample
GID_INSTRUMENT (inst) Music instrument
GID_MUSIC (musi) Music
GID_PICTURE (pict) Single Image
GID_ANIMATION (anim) multiple Images/Animation
GID_MOVIE (movi) Animation with graphics and Sound

In the application there should ideally be a rough preliminary check, because in a painting program there will surely be nothing to show for a music file. A conversion of sound into note signs doesn't exist yet, but could be an interesting application. :-)

The first step

The simplest function available in the datatype.library is determining of the datatype and respectively the datatype concerning the file. The function IDataTypes->ObtainDataType() expects a Taglist, which in the simplest of cases should only contain the name of the file.

  if((lock = IDOS->Lock("dateiname",SHARED_LOCK)))
  {
    if((dtn = IDataTypes->ObtainDataType(DTST_FILE, (APTR) lock, TAG_DONE)))
    {
      ...
      IDataTypes->ReleaseDataType(dtn);
    }
    IDOS->UnLock(lock);
  }

So, that leads us right into the first example program "GetFileType.c", which can be given a file and returns the format type as a result. In case AmigaOS can't do anything with this file it returns "Object not found".

/* Michael Christoph - Musterbeispiel */
/* GetFileTyp - Typ einer Datei ermitteln per Datatypes */
 
/*
** gcc GetFileTyp.c -o GetFileTyp -l auto
*/
 
//#define __USE_BASETYPE__
 
/******************************* INCLUDES *************************************/
 
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/datatypes.h>
#include <proto/iffparse.h>
 
/******************************************************************************/
 
ULONG GetTyp(STRPTR filename)
{
  ULONG typ = 0;
  BPTR lock;
  struct DataType *dtn;
  UBYTE buffer[5];
 
  if((lock = IDOS->Lock(filename,SHARED_LOCK)))
  {
    if((dtn = IDataTypes->ObtainDataType(DTST_FILE, (APTR) lock, TAG_DONE)))
    {
      const struct DataTypeHeader *dth = dtn->dtn_Header;
 
      IDOS->Printf("   Filename: %s\n",filename);
      IDOS->Printf("Description: %s\n",dth->dth_Name);
      IDOS->Printf("  Base Name: %s\n",dth->dth_BaseName);
      IDOS->Printf("       Type: %s\n",IDataTypes->GetDTString((dth->dth_Flags & DTF_TYPE_MASK) + DTMSG_TYPE_OFFSET));
      IDOS->Printf("      Group: %s\n",IDataTypes->GetDTString(dth->dth_GroupID));
      IDOS->Printf("         ID: %s\n",IIFFParse->IDtoStr(dth->dth_ID,buffer));
 
      typ = dth->dth_GroupID;
 
      IDataTypes->ReleaseDataType(dtn);
    }
    else IDOS->PrintFault(IDOS->IoErr(),filename);
    IDOS->UnLock(lock);
  }
  else IDOS->PrintFault(IDOS->IoErr(),filename);
 
  return( typ );
}
 
/******************************************************************************/
 
int main(int argc, char *argv[])
{
  if(argc >= 2) GetTyp(argv[1]);
 
  return( 0 );
}

Here with the file!

In order to actually get the file we also have to use another function with the name IDataTypes->NewDTObject(). This can even be given the name of the file directly (including path), as well as other parameters with Taglist. In case of an error it returns NULL, otherwise an object which have to be released again at the end with IDataTypes->DisposeDTObject().

 if((dtobj = IDataTypes->NewDTObject("sample",
                                    DTA_SourceType,  DTST_FILE,
                                    DTA_GroupID,     GID_SOUND,
                                    TAG_DONE)))
 {
   ...
   IDataTypes->DisposeDTObject(dtobj);
 } 

Merely displaying the file is something which can be handled by the Datatype as well. AddDTObject(), RefreshDTObjects() and RemoveDTObject() take care of this task. For playing back however the Play-Method must be executed:

 IIntuition->IDoMethod(dt,DTM_TRIGGER,NULL,STM_PLAY,NULL);

Usually however you will want to process the file in your own application. In that case IDataTypes->GetDTAttrs(), with which you can request the values, image or sound data for example, will help you along. This time there are two examples concluding this theme: with "ShowPic.c" you can display an image and with "PlaySample.c" you can play back a sample file.

Scaling Image files

Apropos, there is also an option to scale the requested image file straight away, in order to fit it into a window for example. So, in contrast to IGraphics->ScaleBitMap() you can also directly give it the desired height and width. The only disadvantage is that you can only scale the bitmap once before layout (meaning before the method DTM_PROCLAYOUT). The quality of scaling is determined with the tag PDTA_ScaleQuality where 0 if for fast/low quality and 1 for high/slow quality.

 Object *obj;
 if((obj = IDataTypes->NewDTObject(filename,
               DTA_SourceType,    DTST_FILE,
               DTA_GroupID,       GID_PICTURE,
               PDTA_ScaleQuality, 1,
               TAG_DONE)))
 ...
 struct pdtScale pdt;
 pdt.MethodID     = PDTM_SCALE;
 pdt.ps_NewWidth  = width;    /* gew¸nschte Breite */
 pdt.ps_NewHeight = height;   /* und Hˆhe */
 pdt.ps_Flags     = 0;
 if(!(IDataTypes->DoDTMethodA(obj,(Msg)&pdt)))
   IDOS->Printf("Datatype Skalierung fehlgeschlagen

The accompanying example program "ScalePic.c" displays the image when it is started in its original size. However, when you change the window size the image will be scaled up or down to fit.

AHI for sound

The sound.datatype takes care of playing back the sample using AHI (AudioHardwareInterface) and not use the old Paula chip for that anymore. Although there is nothing against playing the sample directly from Datatype, it gives you more flexibility when you use the ahi.device directly for this. Also, because it is not all that complicated, we would like to give you an additional short example. As usual a MessagePort, and for the conversion an IORequest (AHIRequest here) are required in order to open the ahi.device. The AHIRequest can theoretically be copied multiple times as well when multiple samples should be played (simultaneously). After charging AHIRequest with the sample file the asynchronous playback is done with an IExec-SendIO(), (IExec->DoIO() would result in synchronous playback). The function returns immediately while the request is played back in the background. When this is completed (corresponding to completed playback) we receive the matching message on the message port. At the end of the program the device has to be closed and the MessagePort and Request have to be released. The program frame therefore should look like this:

 struct Library    *AHIBase;
 struct MsgPort    *AHImp;
 struct AHIRequest *AHIio;
 if((AHImp = IExec->CreateMsgPort()))
 {
   if((AHIio = (struct AHIRequest *) IExec->CreateIORequest(AHImp,sizeof(struct AHIRequest))))
   {
     AHIio->ahir_Version = 4;
     if(!(IExec->OpenDevice(AHINAME, 0,(struct IORequest *) AHIio,NULL)))
     {
       AHIBase = (struct Library *) AHIio->ahir_Std.io_Device;
       ...
       IExec->CloseDevice((struct IORequest *)AHIio);
     }
     IExec->DeleteIORequest((struct IORequest *)AHIio);
   }18
   IExec->DeleteMsgPort(AHImp);
 }

Connecting sound.datatype and ahi.device

The whole thing becomes truly elegant when the sound files are loaded using datatypes and the ahi.device is used to for co-ordinated playback. In principle the rule is again to use the already discussed method: open ahi.device and datatypes.library and use IDataTypes->NewDataType() to identify the files. With the help of that we now fill the AHIRequest. For that we need to ascertain a few values from Datatype. Especially the address of the file and the playback frequency.

   BYTE *gb_Data; LONG gb_Length, gb_Freq;
   IDataTypes->GetDTAttrs(gb_Obj,
                SDTA_Sample,        &gb_Data,
                SDTA_SampleLength,  &gb_Length,
                SDTA_SamplesPerSec, &gb_Freq,
                TAG_DONE);

The thing is reproduced with IExec->SendIO() and with IExec->Wait() it waits until playback is completed.


 AHIio->ahir_Std.io_Command  = CMD_WRITE;
 ...
 IExec->SendIO((struct IORequest *) AHIio);
 IExec->Wait(1L << AHImp->mp_SigBit);

It is all shown together once more in the example program "PlayAHI.c".

Datatypes internally

Technically speaking the Datatypes are realised as Shared-Library and stored as single files in the directory "SYS:Classes/Datatypes" with the #?.datatype extension. Whether a datatype is active as well is stored with a second file in the directory "SYS:Storage/DataTypes". These files are already automatically activated at the start of Workbench. Inactive interpreters on the other hand are found in "SYS:Storage/DataTypes" and can additionally be started as well when needed by double clicking the icon.

In perspective

In our previous edition we already pointed out the new functions of intuition.library, with which it is even easier to load and use image files from harddisk, without having to do the single steps of datatypes.library. We are talking about IIntuition->ObtainBitMapSource(), IIntuition->ObtainBitMapInstance() and IIntuition->BitMapInstanceControl(). We would like to give you a quick reminder of them in view of this topic.

The other formats, like animation or text, are handled in a similar way. The most important are surely graphics and sounds, which we presented in detail. In the next edition we will return to the surface and we will program a graphical user interface (GUI) using Reaction.

Michael Cristoph Translation: Richard Mulder


KASTEN: Important tags

Here is an overview of the most important Datatype-Tags, to be able to query the files with IdataTypes->GetDTAttrs().

picture.datatype:

 PDTA_BitMap          struct BitMap *  BitMap with the graphic data
 PDTA_DestBitMap      struct BitMap *  graphics data adapted to screen colours
 PDTA_ColorTable      ULONG *          Colour table
 PDTA_NumColors       UWORD            Number of colours used in the image
 PDTA_BitMapHeader    struct BitMapHeader * Graphic-Information (Size etc.)

sound.datatype:

 SDTA_SamplesPerSec   UWORD            Playback speed
 SDTA_Period          UWORD            Playback speed (alternative)
 SDTA_Sample          UWORD *          Sound-File to play 
 SDTA_SampleLength    ULONG            Lenght of the sound file
 SDTA_VoiceHeader     struct VoiceHeader * Sample-Information

text.datatype:

 TDTA_Buffer          STRPTR           Text-File
 TDTA_BufferLen       ULONG            Length of the text files

animation.datatype:

 ADTA_Width           ULONG            Width in Pixels
 ADTA_Height          ULONG            Height in Pixels
 ADTA_Depth           ULONG            Colour depth
 ADTA_Frames          ULONG            Number of frames in the Animation
 ADTA_FramesPerSecond ULONG      Playback speed
 ADTA_Sample          UWORD *         Sound-file of the Animation


BILDER: skalierungsqualitaet.iff: Scaling quality comparison in 4x enlargement for comparison: On the left level 1 with soft edges. On the right with level one the jagged edges become especially obvious on diagonal edges.