
                            Indoor Music System

                 Copyright 1994-1997 Niklas Beisert aka pascal


Indoor Music System (IMS) is a module playback music system for
non-commercial use.

LICENSE:

  You may only use IMS (IMS alwany means IMS or any (derived) parts of IMS,
  use means: use, compile, link, print, execute, distribute, make changes to)
  if you accept the following conditions:

  The author may invalidate this license for any user at any time without
  any reason. If so that user may not use IMS further on.
  This license may change in any version.

  This material is not freeware. You are allowed to copy it without
  restrictions for non-commercial use. No payment of any kind may be charged
  for this product or any combination of products or services including this
  product without the author's authorization and official written license.
  Commercial use is strictly prohibited.

  You take full responsibility for the operation of this software and
  any consequences thereof. The author (Niklas Beisert) cannot accept
  liability for damages or failures arising from the use of this software.

  Your production must clearly state that it uses IMS if the setup
  screen is not used.

  You MAY NOT:

    -use IMS for anything else as stated below
    -charge a fee for IMS, products which use IMS, or products which
      indirectly depend on IMS. You may charge a small fee (not exceeding
      $10) for copying only.
    -distribute modified versions of IMS without clearly stating they are
      not the original version.
    -use IMS if you do not understand this license or parts of it.
    -use IMS without crediting the author.
    -use IMS commercially in any way.
    -use IMS for/in advertisements/commercials.

  You MAY:

    -use IMS for private purposes.
    -use IMS products to which applies the same or an equivalent license.
    -distribute the unmodified distribution archive.
    -modify and distribute modified versions of IMS if:
      -this documentation is included in its original unmodified version.
      -all files which contain source from the original source files include
        the header of original source files.
      -you include a separate documentation about the changes you made,
        with your address (real/email) and contact the author.
      -you comment every change you made plus a summary of changes per file.
      -you do not make major changes like ports to different platforms
        without the authors permission.

  By using this software you indicate that you have fully understood and
  agreed to this license.


What you need:

  -Watcom C++ 10.0 and above
  -Turbo Assembler 3.0 and above


portability:

  I would not call IMS portable at the moment. I've used special Watcom C
  features, most importantly the #pragma aux directive and interface to
  assembly language. There are also several assumptions I made about the
  C compiler which makes a recompile on a different platform impossible.
  I plan to change all the sources for portability. I know that IMS works
  fine under Windows 95/NT with a little driver. If you want to have IMS
  on other platforms contact me, but only if you know what to do and
  would also code and test it.


How to use it all:

  AFAIK most (demo) coders are not interested in sound coding, they just need
  a background player for their production. A simple example of how to set
  up a background player should be enough for you: see test.cpp.
  If you use register calling convention you can use IMS.LIB and BINFILE.LIB,
  otherwise you must remake them with stack calling convention.
  I will release the Lasse Reinboeng sources soon as an example of how to
  use IMS in a real demo/intro. (LASSESRC.ZIP)
  You can enable the PAS driver at the top of ims.obj.


binfile:

  Did I say I like binfile? :) Ok... I made binfile! =} nothing really
  special... just simple and easy to use and enhance. I hate the
  standard C functions for file-io. And fstream is kinda big and still
  not what I want. binfile makes access to binary data files easy.
  binfile is a base class and it can do nothing, but as soon as you overload
  some basic functions (open, close, read, write, seek) you get many
  higher level functions for free, most importantly easy bit, byte, word and
  dword io. With a little coding you use the oop concepts behind it and make
  classes which read directly from archives, access memory instead of
  files, output directly to the soundcard, or implement a stream via tcp/ip.
  Use binfile without restrictions in your programs if you like.

  sbinfile is the binfile for standard file io. open files with
  open(filename, mode), there are only a few modes like openro, openrw
  and opencr.
  abinfile is a binfile contained in another binfile (archive). You can use
  it if you want to put the module in one big file with all the data.


initialization:

  not much to say. just some code and hints.

    imsinitstruct is;
    imsFillDefaults(is);

  then modify "is" to your needs. most values are default values for
  the setup screen. for example:

    is.usequiet=1;
      // quiet option (command line)
    if (!imsInit(is))
      fail

    // use IMS

    imsClose();


xm player:

  The xm player can play XMs and MODs very accurately. Far more accurately
  than the general module player.

    // fil is an open binfile
    xmodule mod;

    xmpLoadModule(mod, fil); // load xm

    xmpLoadSamples(mod); // upload samples to soundcard

    xmpPlayModule(mod); // play
    xmpStopModule();

    xmpFreeModule(mod);


general module player:

  Only a few loaders included in the package. IT cannot be played correctly
  with this player, but ... at least there is a loader. :)

    // fil is an open binfile
    gmdmodule mod;

    mpLoadS3M(mod, fil); // load S3M
    mpReduceSamples(mod); // sorry, some extra work

    mpLoadSamples(mod); // upload samples to soundcard.

    mpPlayModule(mod);
    mpStopModule();

    mpFree(mod);


mixer control:

  Hey, there are some guys out there who do not own a device like GUS
  which does all the mixing for you. Actually there are a lot, so
  do not ignore them!
  If you do screen synchronization the mixer background routines might
  interfere. Therefore you can set the size of the playback buffer, you
  can call the mixer explicitly and you can make the background routines
  only update the buffer in an emergency situation.
  Currently the mixer will be called about 70 times a second (there is no
  nice way to change it yet).
  To set the buffersize set bufsize in the imsinitstruct to 65536 times the
  length of the buffer in seconds. Note that the buffer is limited to 64k.
  If you want to update the buffer manually (eg. once per frame is a good
  idea, when you expect high framerates) call mcpIdle (buf only if mcpIdle
  is not zero: if (mcpIdle) mcpIdle();)
  To make the background routines sleep until there was no foreground call
  (mcpIdle) set pollmin in imsinitstruct to 65536 times the critical time
  in seconds. (Set it to a value reasonably smaller than bufsize of course!)


synchronization/timing:

  At the moment I can only think of one reliable way to synchronize to
  the music. There is a function which gives you a time value which
  is perfectly synchronized with the music. Furthermore there is a
  function which calculates the same time value from a specific module
  position. This function should be called at the beginning of your
  program or you precalclate the time values with another program and
  insert them into the code. The timer starts with zero the the very
  first tick of the module. Note that before the first tick the timer
  will be negative. It will increase by 65536 per second. All your
  timing should be based on the timer function. I've heard that some
  guys use a periodically called function to do timing... All I can say
  is that I do not support this method, it's not reliable. It's not
  reliable either to use the system timer for timing. If you set
  up a soundcard to play something at 44.1kHz, it means that it will
  sound as if it did, although after some minutes you get a lag of a
  second, which you'll definitely notice!

  IMS does not (yet) offer automatic screen synchronization. I never needed
  it and it was a pain to figure out how to. :) So, if you find a reliable
  way to do so, don't hesitate and write me (fine, clean working code).
  Do not clear the interrupt flag for a longer period of time or wavetable
  devices will get into trouble. With mixer control you can do manual screen
  sync, but it does not work with wavetable devices... :(

  functions:
    mcpGet(-1,mcpGTimer)
      returns timer value
    xmpPrecalcTime(module, startpos, calc, n, ite)
    gmdPrecalcTime(module, startpos, calc, n, ite)
      module position to timer value calculation:
        startpos: starting position: (order<<8)|row
        calc: array of positions and timer values
        n: number of positions to calculate
        ite: maximum number of ticks to process
        returns: 0: failed otherwise 1.
      calc[x][0] contains the event:
        (order<<16)|(row<<8)|tick: module position
                               -1: module loops
                        -256-sync: syncvalue hit
      calc[x][1] must be initialized with -1 or minus the number of times
        the event must occur before the time is calculated. it will contain
        the time value afterwards.
      ite must be set to a reasonably high value like 10000 or 100000,
        after that many ticks the function will fail if not all events were
        found.


future enhancements:
  -The structure of IMS is not final and there have been many changes lately,
    I still have to figure out several things. Expect changes.
  -Some changes will always be made, so do not expect that you can use your
    old sources without changes with new releases. This is not a commercial
    project (yet) and if you complain your license might void.
  -sound, not just music (ie. foreground playing)
  -portability


contact:

  Niklas Beisert
  Oberstrasse 84
  20149 Hamburg
  Germany

  nbeisert@physik.tu-muenchen.de

  send your questions to: null@nowhere.nil
  complain online at: www.haltsmaul.com


thanks, source and documentation used for creating IMS:

  Tammo Hinrichs: for testing / XM help / Interwave (reverb) code
  Sahara Surfers: PAS driver ported from MIDAS.
  Jarno Heikkinen: Interwave code (in MIDAS).
  Omega player: AWE coding example.
  Judge Dredd: AWE documentation.
  Ilya Naumov: ESS sources.
  ???: for letting me test and bugfix ESS on his computer.
  GUS SDK: GUS / WSS coding.
  And of course all the guys who helped me getting cubic player
    and IMS the way it is now.
