








       [1mProtracker derivative Player development HOWTO[0m

                [4mSimon[24m [4mPeter[24m [4m<dn.tlp@gmx.net>[0m


[1m1.  Introduction[0m


     If you want to create a player for a Protracker-deriva-
tive format, the generic Protracker player  [4mCmodPlayer[24m  that
comes  with  AdPlug  can  be  of great help. It supports all
standard Protracker features, plus a good set of  extensions
to cope with most derivative formats.


     When  writing a player for a Protracker-derivative for-
mat, it is almost  always  better  to  use  and  extend  the
[4mCmodPlayer[24m class, instead of writing a whole new player.


[1m2.  Features[0m


     In  addition to handling your data just like the origi-
nal Protracker would, AdPlug's generic Protracker player has
the following extra features:


+o    Special Arpeggio lists, just like in the SA2 format.

+o    Extendable set of up to 256 note commands.

+o    Up to 16 behaviour changing flags.

+o    Arbitrary  numbers  of  rows, patterns, tracks, instru-
     ments and orderlist entries.


     The only current limitation is that it has a maximum  9
voice  polyphony, which isn't really a limitation, since the
OPL2 is just 9 voices, anyway.


[1m3.  Defaults[0m


     For historical reasons,  [4mCmodPlayer[24m  sets  defaults  to
some values that needn't be initialized by you. These are:












                             -2-


+o    The orderlist is preallocated to 128 entries.

+o    The patterndata is preinitialized to 64 patterns with 9
     channels and 64 rows each.

+o    The instruments array is preallocated  to  250  instru-
     ments.


     These  are mostly standard Protracker limits. They stem
from the original SA2 defaults, for which this was once  the
player. Look at the [4mCmodPlayer[24m constructor for info on which
variables are involved.


[1m4.  Protracker Loaders[0m


     When  you  decided  to  extend  the  [4mCmodPlayer[24m  class,
instead  of writing a whole new player, you do this by writ-
ing a loader for it. This is done very similarily to writing
a  unique player for AdPlug. Thus, reading the [1mAdPlug Player[0m
[1mdevelopment HOWTO [22mis recommended for this task, too.


     Instead of naming your  player  class  [4mCxxxPlayer[24m,  you
should  name  it  [4mCxxxLoader[24m or something appropriate if the
name  is  already  taken.  You  then  publicly  inherit  the
[4mCmodPlayer[24m  class  and  fill  the missing methods with code.
These are now:


     static CPlayer *factory(Copl *newopl);
     bool load(istream &f, const char *filename);
     float getrefresh();
     std::string gettype();



     Plus maybe some (or all)  of  the  other  informational
methods, listed in the [1mPlayer development HOWTO[22m.  Refer also
to that HOWTO to see what the above methods are about.


[1m5.  Designing your loader[0m


     File validation and initial loading is the same  as  it
would  be  with any other player. One speciality is that you
have to call [4mrewind(0)[24m  whenever  you  completely  loaded  a
valid  file.  Don't  call  it when you just exit your loader
because the file was invalid, etc...











                             -3-


     The Protracker player needs at least an orderlist,  the
patterns  and the instruments to function. Most of the time,
you have to convert these between your file's  ordering  and
[4mCmodPlayer[24m's  internal  ordering.  Look  in  the  file  pro-
track.cpp, [4mCmodPlayer[24m's actual sources, for a  list  on  how
these constructs are ordered internally.


     Also, please look up the [1mDefaults [22msection in this docu-
ment, to see if you need to reallocate any of the  defaults.


     There are some variables, that you automatically inher-
ited with your new loader, that you have to set in order  to
tell  the Protracker player something about your loaded mod-
ule. These are the  following  (default  preset  values  are
printed in brackets after the variable name):


[1mlength (unset):[0m

     The   orderlist  length.  When  [4mCmodPlayer[24m's  orderlist
pointer equals or is bigger than this length, it is automat-
ically wrapped around to [4mrestartpos[24m.


[1mtrackord (0):[0m

     Refer to [1mLoading Patterns [22mbelow on this one.


[1mrestartpos (unset):[0m

     The  restarting  position in the orderlist, when [4mlength[0m
is exceeded.


[1mactivechan (0xffff):[0m

     A flag array, telling  the  player  which  channels  in
every  pattern  are  actually  active  and to be played. The
ordering of this variable is a bit awkward, so  be  careful!
It  is  a 16-bit unsigned short, holding the activeness of a
channel in each of its bits, [1mstarting at the  highest  order[0m
[1mbit[22m.   It also holds values for 16 channels and you can only
use the lower 9.  So, to set channel 0 active, you  have  to
set  bit  15  (counting from bit 0) to 1 and so on. You only
use the upper 9 bits of this  variable.  Setting  the  lower
bits will have no effect.














                             -4-


[1minitspeed (6):[0m

     Initial protracker-compatible speed setting.


[1mbpm (unset):[0m

     Initial  protracker-compatible  bpm  (sometimes  called
tempo) setting.


[1mflags (Standard):[0m

     Refer to [1mSpecial Flags [22mbelow.


[1mnop (0):[0m

     The number of patterns in your module. You  don't  need
to  set  this  value.  If you leave it at 0, [4mCmodPlayer[24m will
automatically determine  the  number  of  [1maccessed  [22mpatterns
(which in no way need to be the same as the actual number of
patterns in your module) from the orderlist, in the [4mrewind()[0m
method.  The  value serves only informational purposes, any-
way. It is not needed for the actual playback. If you  think
you  know  better  than  [4mCmodPlayer[24m,  feel free to set it to
something else and [4mCmodPlayer[24m won't  touch  it  anymore  and
display your value instead.


[1m6.  Loading Patterns[0m


     AdPlug's  Protracker player stores the tracks (or chan-
nels, as some may call them), that make up a pattern,  in  a
way that makes it possible for you to reorder and reuse them
in an easy way. This also  makes  storing  patterns  in  the
classic way a bit awkward.


     If  you just want to store your tracks the classic Pro-
tracker   way   (usually   the   case),   first   use    the
[4mCmodPlayer::init_trackord()[24m  method  to do an initial setup.
Then store your tracks in a sequential manner, counting from
0, in the [4mtracks[24m array. That is, for the first 9 channels of
your first pattern, use [4mtracks[0..9][24m.  The second  dimension
of this array holds the rows of each channel. For the next 9
channels, you use [4mtracks[10..19][24m, and so on.


     If you want to make use of the reorder/reuse feature of
the [4mtrackord[24m array, please refer to the sa2.cpp source file.
This player utilizes this method.  Basically,  the  [4mtrackord[0m
array  tells  the player which track out of the [4mtracks[24m array









                             -5-


it has to insert for each of the  9  tracks  of  a  pattern.
Thus,  the first dimension of this array stands for the cor-
responding pattern and the next dimension holds the  entries
for all the 9 tracks.


     [4mCmodPlayer[24m  orders its note data, in the [4mTracks[24m struct,
the following way:


     [4mnote[24m holds the note value. A value of 0 means no  note.
A  value  of  127  means  "key off". Values from 1 to 96 are
actual notes to be played. Everything else is  ignored.  The
octaves are encoded with the actual note values. Thus, notes
from 1 to 12 are the 12 halftone-steps of the first,  lowest
octave, 13 to 24 are those of the next lowest octave, and so
on. Refer to the source code to see  which  frequencies  are
actually associated with the note values.


     [4minst[24m  holds the instrument to be played with this note.
Again, a 0 value means no instrument is associated with this
note and the last active instrument is taken instead. Other-
wise, the instrument with the number [4minst[24m minus 1 is fetched
from the [4minst[24m array (it's 0 based).


     [4mcommand[24m  holds the command to be issued with this note.
All available commands are listed in the following table:

     |                             |                   |
[1mValue[22m|[1mCommand description           [22m|[1mParameters          [22m|[1mRange[0m
-----+-----------------------------+-------------------+-------
  0xy|Arpeggio                      |xy=1st note,2nd note|[0-F]
  1xx|Frequency slide up            |xx=sliding speed    |[0-FF]
  2xx|Frequency slide down          |xx=sliding speed    |[0-FF]
  3xx|Tone portamento               |xx=sliding speed    |[0-FF]
  4xy|Vibrato                       |xx=speed,depth      |[0-F]
  5xy|Tone portamento & volume slide|xy=vol up|vol down  |[0-FF]
  6xy|Vibrato & volume slide        |xy=vol up|vol down  |[0-FF]
  7xx|Set tempo                     |xx=new tempo        |[0-FF]
  8--|Release sustaining note       |                   |
  9xy|Set carrier/modulator volume  |xy=car vol|mod vol  |[0-F]
 10xy|SA2 volume slide              |xy=vol up|vol down  |[0-F]
 11xx|Position jump                 |xx=new position     |[0-FF]
 12xx|Set carr. & mod. volume       |xx=new volume       |[0-3F]
 13xx|Pattern break                 |xx=new row          |[0-FF]
 14??|Extended command:             |                   |
   0y|Set chip tremolo              |y=new depth         |[0-1]
   1y|Set chip vibrato              |y=new depth         |[0-1]
   3y|Retrig note                   |y=retrig speed      |[0-F]
   4y|Fine volume slide up          |y=vol up            |[0-F]
   5y|Fine volume slide down        |y=vol down          |[0-F]










                             -6-

     |                             |                   |
[1mValue[22m|[1mCommand description           [22m|[1mParameters          [22m|[1mRange[0m
-----+-----------------------------+-------------------+-------
   6y|Fine frequency slide up       |y=freq up           |[0-F]
   7y|Fine frequency slide down     |y=freq down         |[0-F]
 15xx|SA2 set speed                 |xx=new speed        |[0-FF]
 16xy|AMD volume slide              |xy=vol up|vol down  |[0-F]
 17xx|Set instrument volume         |xx=new volume       |[0-3F]
 18xx|AMD set speed                 |xx=new speed        |[0-FF]
 19xx|RAD set speed                 |xx=new speed        |[0-FF]
 20xx|RAD volume slide              |xx=vol up/down      |[0-FF]
 21xx|Set modulator volume          |xx=new volume       |[0-3F]
 22xx|Set carrier volume            |xx=new volume       |[0-3F]
 23xx|Fine frequency slide up       |xx=freq up          |[0-FF]
 24xx|Fine frequency slide down     |xx=freq down        |[0-FF]
 25xy|Set carrier/modulator waveform|xy=carr wav|mod wav |[0-3,F]
 26xy|Volume slide                  |xy=vol up|vol down  |[0-F]
 27xy|Set chip tremolo/vibrato      |xy=tr depth|vb depth|[0-1]
 28xy|DTM frequency slide           |xy=frames up|down   |[0-F]
255--|No operation (NOP)            |                   |

[1mTable 1.  [22mEffect commands


     The [4mparam1[24m and  [4mparam2[24m  variables  hold  the  command's
parameters.  These are command-dependant. Refer to the table
above to see what they do with  each  of  the  commands  and
their  value  ranges.  An  [4mxx[24m in the [1mParameters [22mcolumn means
that [4mparam1[24m and [4mparam2[24m  form  one  2-digit  parameter,  with
[4mparam1[24m  being  the  leftmost decimal. Otherwise, [4mx[24m refers to
[4mparam1[24m and [4my[24m to [4mparam2[24m.


[1m7.  Loading Instruments[0m


     For the instrument data, [4mCmodPlayer[24m stores  it  in  the
[4minst[].data[][24m array, in the following way:

     |        |                                               |
[1mIndex[22m|[1mOperator [22m|[1mDescription                                     [22m|[1mOPL2[0m
-----+--------+-----------------------------------------------+----
  0  |Channel  |Feedback strength / Connection type             |0xc0
  1  |Modulator|Amp Mod / Vib / EG type / Key Scaling / Multiple|0x20
  2  |Carrier  |Amp Mod / Vib / EG type / Key Scaling / Multiple|0x23
  3  |Modulator|Attack Rate / Decay Rate                        |0x60
  4  |Carrier  |Attack Rate / Decay Rate                        |0x63
  5  |Modulator|Sustain Level / Release Rate                    |0x80
  6  |Carrier  |Sustain Level / Release Rate                    |0x83
  7  |Modulator|Wave Select                                     |0xe0
  8  |Carrier  |Wave Select                                     |0xe3
  9  |Modulator|Key scaling level / Operator output level       |0x40
 10  |Carrier  |Key scaling level / Operator output level       |0x43

[1mTable 2.  [22mInstrument data ([4minst[].data[][24m) values









                             -7-


     There are 3 extensions, [4mCmodPlayer[24m imposes to the stan-
dard instrument data.  These  are  also  stored  within  the
[4minst[][24m array.


     First,   there's   the   "Special  Arpeggio".  This  is
explained in the [1mSpecial Arpeggio [22msection, below.


     Next we got the [4mslide[24m variable.  This  is  a  pre-slide
value  that  is  always  added to the frequency of the note,
whenever this instrument is to be played.


     Finally, there's the [4mmisc[24m variable. This  is  just  the
holder  for  the  value  of  the  0xbd  register  (i.e.  the
"drums'n'misc" register) of the OPL2.


[1m8.  Special Flags[0m


     The [4mflags[24m variable holds special flags  to  change  the
behaviour of the player. These are:


[1mStandard:[0m

     Act   like  standard  Protracker  would.  This  is  the
default.


[1mDecimal:[0m

     Command parameters are decimal values, not hexadecimal.
For split parameter commands (i.e. commands with two parame-
ters, like 0xy), this has no effect,  since  decimal  values
would  be  from  0 to 9, anyway. But commands that take both
parameters as one value (i.e. like 1xx) now take values from
0  to  99 and handle them properly (i.e. decimal wrap-around
is now at 9 to 10 and not at F to 10).


[1mFaust:[0m

     Treat the files like [1mFaust  Music  Creator  [22mdoes.  This
tracker uses a different volume handling scheme. In standard
Protracker, the volume is computed as follows:

     final volume = channel volume = instrument volume

In [1mFaust Music Creator[22m, it is done like this:











                             -8-


     final volume = (channel volume + instrument volume) / 2



[1mNoKeyOn:[0m

     This prevents the OPL2 key off/on toggle on every newly
played note. Some trackers require it that way...


     These  flags can be set and unset at any time. To set a
flag, just binary [1mOR [22mit with the  [4mflags[24m  variable.  Use  the
[4menum[24m  [4mFlags[24m  data  type, defined in the [4mCmodPlayer[24m class for
this purpose.


[1m9.  Deconstruction[0m


     Be careful when  specifying  your  own  deconstructors!
These  will  generally  override [4mCmodPlayer[24m's deconstructor,
because it is defined virtual. Since [4mCmodPlayer[24m's own decon-
structor  normally handles all deconstruction work automati-
cally, you would have to do this manually now.


     To ease this process,  there's  a  method  [4mdeallocate()[0m
that  you  inherited with your loader. Call this in your own
deconstructor and it will handle the deconstruction  of  the
[4mCmodPlayer[24m-internal objects automatically, as usual.


[1m10.  Special Arpeggio[0m


     To  use  the  "Special  Arpeggio" facility, you have to
initalize it first. Use  the  [4minit_specialarp()[24m  method  for
this purpose.  [4mCmodPlayer[24m's deconstructor or [4mdealloc()[24m auto-
matically handle the deinit for you.


     The special arpeggio uses  the  4  variables  [4marpstart[24m,
[4marpspeed[24m, [4marppos[24m and [4marpspdcnt[24m of the [4mInstrument[24m struct.

[4m[TODO:[24m [4mactually[24m [4mexplain.[24m [4mRefer[24m [4mto[24m [4msa2.[cpp,h][24m [4mand[24m [4mthe[24m [4morigi-[0m
[4mnal[24m [4mSA2[24m [4mdocs[24m [4min[24m [4mthe[24m [4mmeantime.[24m [4mThe[24m [4mfollowing[24m [4mtable[24m [4msummarizes[0m
[4mthe[24m [4mspecial[24m [4mcommands.][0m

      |
[1mValue [22m| [1mCommand description[0m
------+-------------------------
 252  | Set carr. & mod. volume
 253  | Release sustaining note










                             -9-

      |
[1mValue [22m| [1mCommand description[0m
------+-------------------------
 254  | Arpeggio loop
 255  | End of special arpeggio

[1mTable 3.  [22m"Special Arpeggio" commands






















































