Linux Demo Coding

sind / pdg

Linux has got more and more users in the last few years. The amount of software available for Linux is huge and growing. To my (and many others') disappointment there haven't really been many Linux demos around. It's a shame, as in my opinion coding under Linux is much easier than under Windows, and still it provides the same properties and much more.

1. Programming with svgalib

Most Linux/i386 distributions include svgalib, so let's deal with that first. In my point of view, svgalib is best for the good old mode 13h, 320x200x256 colours:

  #include <vga.h>
  #include <stdio.h>

  int main()
  {
      int err;

      err=vga_setmode(G320x200x256);

      if(err)  // mode not available (no vga available?)
      {
          fprintf(stderr,"VGA mode 320x200x256 not available.\n");

          return -1;
      }

      ... [ do something beautiful ] ...

      vga_setmode(TEXT);  // return to textmode
  }

The video memory location is not fixed under Linux: svgalib stores the address of the frame buffer in a pointer named 'graph_mem' (type unsigned char *). The frame buffer is the same as in mode 13h under MS-DOS.

So putting a pixel in an unoptimized way will be something like this:

  void putpixel(int x, int y, unsigned char c)
  {
      graph_mem[(y*320) + x] = c;
  }

As we cannot have direct access to the I/O ports under Linux (yes, it is possible, but not recommended for user level programs), we have to use svgalib functions to alter the palette:

  void vga_setpalette(int index, int r, int g, int b);

Index is the colour you want to change, and r,g,b are the components (0-63).

Note: svgalib supports also many other modes, up to 1600x1200x32bit, but it usually lacks the linear frame buffer support, so all resolutions higher than 320x200 are banked (and too slow for demos).

2. Programming with LibGGI

Svgalib is practically limited to the 320x200x256 mode, which isn't really enough for modern demos. KGI (Kernel Graphics Interface) seems to solve some of the problems of svgalib, but as it requires a kernel patch that most Linux users don't have installed, it isn't a real alternative. Also the X Windowing system provides high-resolution high-colour modes, but at least in my opinion it is far too complex as a platform for demonstrations, as we usually need only the linear frame buffer access.

LibGGI (http://www.ggi-project.org) seems to be a solution for my problem. It tries to use any available way of getting a linear frame buffer for your application. It is a must if you want to code a demo for Linux. It has more features than svgalib, and therefore it's a bit more complicated.

In order to use LibGGI, you must download the sources, compile and install it on your system. You don't need to install the kernel patches, LibGGI works fine without them.

The following code will set up the 320x200 mode with as many colours as available:

  #include <ggi/ggi.h>
  #include <stdio.h>

  ggi_visual_t visual;
  ggi_mode mode;

  int main()
  {
      ggiInit();
        // must be called before any other LibGGI function call

      visual=ggiOpen(NULL);
        // opens the visual on the default display target

      ggiCheckGraphMode(visual, 320, 200, 320, 200, GT_8BIT, &mode, NULL);
        // checks if mode (320x200 physical, 320x200 virtual, at least 8bits)
        // is available in 'visual' and suggests the best matching mode in
        // 'mode'

      ggiSetMode(visual, &mode);
        // opens the mode

      ... [ do something beautiful ] ...

      ggiClose(visual);
        // closes the visual

      ggiExit();
        // must be called after all other LibGGI function calls
  }

Usually it's not very comfortable to let the system choose which graphic mode you have to use. To force LibGGI to open a 320x200 mode with 16bit of colours, change the mode checking and opening lines to the following:

      if(ggiCheckGraphMode(visual, 320,200, 320,200, GT_16BIT, NULL, NULL))
          return -1;  // 320x200 with 16bit colors not available

      ggiSetGraphMode(visual, 320,200, 320,200, GT_16BIT);
        // now we got the mode we wanted

LibGGI provides a large set of graphical primitives, but at least for me they haven't been very useful, and it would be impossible to discuss them here, so let's get to the point, the linear frame buffer with LibGGI:

  ggi_directbuffer_t db;
  ggi_pixellinearbuffer *plb;
  void *lfb;

      ... set up the mode ...

      if(( ggiDBGetBuffer(visual, &db) ) ||
         ( ggiDBGetLayout(db)!=blPixelLinearBuffer ))
      {
          // no DirectBuffer mechanism available: close the mode and exit

          ggiClose(visual);
          ggiExit();
          return -1;
      }

      plb = ggiDBGetPLB(db);
      if(!plb)
      {
          // no pixel linear buffer available: close and exit

          ggiClose(visual);
          ggiExit();
          return -1;
      }

      lfb = (void *)plb->write;

At this point, we will either be out or have a writable frame buffer pointed to by 'lfb'. Now we can inspect the 'mode' to see how the pixels are stored in the buffer (or if we have forced a specific mode, we know it already).

3. Sound programming

Like most of the device programming, also sound programming under Linux is very easy. If the system supports waveform output (and you are allowed to access that resource), you are able to open a special file (/dev/dsp) and just write the sample data. And the controlling of the device is almost as easy.

The following program will produce a high square wave on your sound card:

  #include <unistd.h>
  #include <fcntl.h>
  #include <stdio.h>
  #include <linux/soundcard.h>

  void main()
  {
      int dsp;
      int param, c;
      char data;

      dsp=open("/dev/dsp", O_APPEND);
      if(dsp)
      {
          perror("/dev/dsp");
          return -1;
      }

      ioctl(dsp, SNDCTL_DSP_RESET);
        // reset soundcard

      param=8000;

      ioctl(dsp, SNDCTL_DSP_SPEED, ¶m);
        // set sample frequency to 8kHz

      for(c=0; c<8000; c++)
      {
          data=c&1 * 255;
          write(dsp, &data, 1);
      }

      close(dsp);
  }

If you are interested in /dev/dsp or other Linux sound device files, you should read '/usr/include/linux/soundcard.h'.

And if you don't want to write your own sound system for Linux, there are always Midas Sound System (http://www.s2.org/midas) and many other solutions.

-- tuomas niinimaki [ sind / pdg ]
-- comments etc.: sind@vip.fi