Porting tracker

Tracker 4.44

# Chapter 5: Porting tracker to another architecture

If possible, you should use the same coding conventions as I do.

- All of tracker source code is archived with `RCS`. Use `RCS` to maintain tracker if you can.
- For me, tabs correspond to three spaces.
- Standard file header:

        /* st_read.c
           vi:ts=3 sw=3:
         */

        /* $Id$
         * $Log$
         * Revision 1.1  1995/09/03 15:44:31  espie
         * Initial revision
         *
         */

        /* description of the file if applicable */
        #include "defs.h"

        #include <system_files>

        #include <extern.h>

        ID("$Id$")

  The `$Id$` and `$Log$` entries are filled by RCS. ``defs.h`' includes some standard header files: ``config.h`', ``stdio.h`', ``stdlib.h`', ``string.h`'. It also includes some useful standard definitions. You are advised to read it.

- My C is ANSI, but should be acceptable to K&R compilers. This means that prototypes use the form ``function P((int param));`', where P expands to a prototype or a `()` according to ``config.h`', and that actual function declarations should use old type prototype. You don't have to care to much about that as I'm most probably be switching to full ANSI soon.
- Tracker uses ANSI functions, with some smattering of Unix-isms where applicable. Be aware that tracker should stay portable, try to use ANSI C functions whenever possible, and to encapsulate system functions where needed.
- Tracker needs a decent address space, not a toy computer like an IBM PC.
- Tracker needs files and pipes, it's real difficult to port to toy computers like MacIntoshes.

There are several parts of tracker that need porting.

## 5.1: The audio interface

In case samples need to be in a specific part of memory, add `#define SPECIAL_SAMPLE_MEMORY` to ``config.h`' and provide suitable `alloc_sample` and `free_sample` functions as per ``extern.h`'.

If your audio hardware cannot emulate an Amiga directly (see Amiga audio hardware), you will have to use resampling, See Resampling details.

Basically, you will build a specific ``audio.c`' file for your architecture that holds two important functions:

`open_audio(freq, stereo)` opens the audio hardware for a given resampling frequency, and stereo or mono mode. This returns the actual resampling frequency nearest to the frequency asked that will actually be used. For your first try, open the audio channel in a suitable stereo or mono mode at a fixed rate.

`output_samples(left, right, n)` adds two audio samples to the stream in progress. Both samples have n bit resolution.

Other functions in ``audio.c`' as documented in ``extern.h`' can mostly be replaced by suitable stubs.

This audio architecture will probably change for release 5, in order to provide for more flexibility, but you shouldn't have to worry too much about that yet, as I will provide a `compatibility interface'.

You have some templates of suitable configuration files in the directory ``Arch/Port`'. Specifically, this ``config.h`' removes most of tracker system dependencies. ``ui.c`' is a minimal user interface file that needs only stdio to work, and ``audio.c`' is a minimalist audio interface derived from the Sparc audio interface.

Create a directory for your architecture, copy these files there, update the ``Makefile`' to add an entry for your architecture. You need to edit ``config.h`', since as shipped it doesn't work, and to implement the base functions as discussed in ``audio.c`'. Don't forget to use the set of routines in ``common.c`'. With them, you can get most audio hardware running.

When this part works, try to implement the remaining of the audio functions. First, try to have parameters working, like different sampling rates, mono and stereo, then try to add the advanced features.

## 5.2: The user interface

Once the audio works, try to fix the user interface up. If your system looks like a standard Unix, you'll just have to discover how to put your terminal in cbreak mode.... Usually, the ``Arch/Unix/ui.c`' file together `#define USE_SGTTY` or `#define USE_TERMIOS` will be enough. If you are not under Unix, this might be more difficult. Also note `run_in_fg`, which decides whether to do all this stuff or not, since background processes tend to fail if they try to output something.

Recently, I've added support for xterms (triggered by `PREF_XTERM`) and for color terminals (triggered by `PREF_COLOR`). `PREF_XTERM` is set by the TERM environment variable in ``main.c`', `PREF_COLOR` is set according to the compilation switch `COLOR_IS_DEFAULT`. Note that both of these settings may be overriden by command line options.

If your machine uses another color model, you will have to add suitable definitions to ``color.c`'. Note that I'm not satisfied with the way color currently is defined, so I might change this stuff.

## 5.3: File systems

To support compression, your system must have popen and pclose. If it does not, you'll have to modify ``open.c`' extensively if you want compression. Try to remove `#define NO_PIPES` from ``config.h`' and recompile ``open.c`' to check whether compression works or not. You'll also have to adapt ``compression_methods`' to your system.

I'm currently investigating into a more supple variant of tracker that would use sockets instead, so that all the decompression shebang would lie with a perl script (that could also cache file, access the network, and everything).

You also need `stat`, `S_ISDIR`, `readdir` for the automatic expansion of directories in ``play_list.c`' to work[1].

## 5.4: Beyond the simple port

I would like some people to work on more interesting ports. The Amiga version of tracker, for instance, includes some significant improvements, but I have no time myself to be writing an X-Window port of tracker. Due to the asynchronous nature of tracker, the audio output is usually buffered. Some events, like the scrolling display, should occur when the corresponding audio event is played. The Amiga, Sparc, and NeXT versions include a post-synchronization function. They use the `sync_audio` function[2]

Basically, `sync_audio` inserts a hook into the audio pipeline: a function to call, with some parameters, when the audio stream finally reaches the current point. More precisely, there are two functions: one to call when the audio stream reaches this point, and an alternate function to call to clean up if the audio stream never reaches this point. For instance, when you depress `n` on the keyboard, it would be most unpractical to have all the accumulated scrolling info suddenly appearing on the screen, so it is flushed. But there is some memory accounting involved, hence the flushing function calls `free` on each line involved.

[1] I'm going to make this much more portable soon

[2] Well... the Amiga version does not, but it should. I just haven't updated it yet.