© Christopher Bazley, 2009
Version 0.07 (02 May 2020)
Download SF3KtoProT (61 KB Zip archive, includes source code).
Alternatively, you can browse the source code on GitHub.
Star Fighter 3000 is a three dimensional combat-dedicated flight action shooter which was first published in 1994 for 32-bit Acorn RISC OS computers. This program converts the music tracks from their original esoteric file format (understood only by the game's own music player) into standard Amiga ProTracker V1.1B song/module format. Most of the original features of the music can be replicated fairly accurately in ProTracker format.
The game's own music and sound effects player is a relocatable module named 'SFX_Handler'. For brevity, I have referred to it by that name throughout the remainder of this manual.
The supplied executable file will only work on RISC OS machines. It has not been tested on any version of RISC OS earlier than 4, although it should also work on earlier versions provided that a 'SharedCLibrary' module is active. It is known to be compatible with 32 bit versions of RISC OS.
You will obviously require a copy of the game 'Star Fighter 3000' from which to rip the music. It is free to download (as a 1195 KB Zip archive)
Until release 2.02 of the game, the sound sample data and music tracks were incorporated into 'SFX_Handler'. You need a version where this data is instead supplied in separate files. Compressed music data files can be found inside the !Star3000 application, in the sub-directory named "Music". Raw sound sample data files suitable for used with this program are located in the sub-directory "Samples".
Ensure that the !Star3000 application has been 'seen' by the Filer, so that the system variable Star3000$Dir has been set.
Hold down the Shift key and double-click on the !Star3000 application to open it. Copy the supplied 'index' file into the sub-directory that contains sound sample data files (as !Star3000.Samples.index). This file should require no modification because it has been tailored for the game (which configures 'SFX_Handler' using similar parameters).
Set the current selected directory to that containing the 'SF3KtoProT' program. On RISC OS 6, that can be done by opening the relevant directory display and choosing 'Set work directory' from the menu (or giving the directory display the input focus and then pressing F11).
Press Ctrl-F12 to open a task window and then invoke the music conversion program using the following command:
*SF3KtoProT -v <Star3000$Dir>.Samples <Star3000$Dir>.Music.BonusLevel b/mod
(A forward-slash rather than a dot is used to separate file names from file extensions on RISC OS. This is merely a convention; RISC OS instead stores the type of files in hidden metadata.)
This should convert the Star Fighter 3000 music file 'BonusLevel' into a ProTracker module, using sound samples taken from the 'Samples' directory inside the !Star3000 application and storing the output in a file named 'b/mod'. The '-v' switch enables verbose output, which shows what is happening during the conversion process.
By varying the third argument to the 'SF3KtoProT' program, any of the other files in the !Star3000.Music directory can also be converted to ProTracker format.
If the Filer has already 'seen' an application which claims file type &CC5 ('TeqMusic' - allocated to Krisalis) then you should simply be able to double-click on the output files in order to play the music. If that causes an error box saying "An application that loads a file of this type has not been found by the Filer" then you must explicitly load a tracker player such as DigitalCD or Digital Symphony, before dragging the output file to the player's iconbar icon.
Usage:
SF3KtoProT [switches] <samples-dir> [<input-file> [<output-file>]]
Or
SF3KtoProT -batch [switches] <samples-dir> <file1> [<file2> <file3> .. <fileN>]
When invoking 'SF3KtoProT', you must specify the name of a directory containing the sound sample files to be incorporated in the output ProTracker module. Unlike ProTracker modules, SF3000 music files do not incorporate sound samples (which makes sense given that each piece uses a subset of the same instruments). Suitable sound samples are supplied with the game, inside the !Star3000.Samples directory.
Because the sound sample files consist of raw data in 16 bit little-endian signed linear format, there is nowhere to keep meta data. Rather than hard- wiring the tuning value, repeat offset and type of each sample into the conversion program, it reads this data from an index file (the format of which is described in the section on file formats). By default, it looks for an index file in the same directory as the sample files, but you can force it to look elsewhere by using the '-indexfile' switch. That may be useful if the game is on read-only media such as a CD-ROM.
Single file mode is the default mode of operation. Unlike batch mode, the input and output file names can be specified separately (or not at all). An output file name can be specified after the input file name, or, by means of the '-outfile' switch, before the name of the directory containing the sound samples.
If no input file is specified, input is read from 'stdin' (the standard input stream; keyboard unless redirected). If no output file is specified, output is written to 'stdout' (the standard output stream; screen unless redirected).
All of the following examples read input from a file named 'foo' and write output to a file named 'bar':
*SF3KtoProT <Star3000$Dir>.Samples foo bar
*SF3KtoProT -outfile bar <Star3000$Dir>.Samples foo
*SF3KtoProT -outfile bar <Star3000$Dir>.Samples <foo
*SF3KtoProT <Star3000$Dir>.Samples foo >bar
*SF3KtoProT <Star3000$Dir>.Samples <foo >bar
Under UNIX-like operating systems, output can be piped directly into another program.
Convert a SF3000 music file named 'foo' into a compressed ProTracker module file named 'bar.gz':
SF3KtoProT ~/star3000/samples foo | gzip > bar.gz
Batch processing is enabled by the switch '-batch'. In this mode, multiple files can be processed using a single command. The output is always saved to a file with a name derived from the input file's name, which means that programs cannot be chained using pipes. At least one file name must be specified.
Convert a SF3000 music file named 'foo' to a ProTracker module file named 'foo/mod':
*SF3KtoObj -batch <Star3000$Dir>.Samples foo
Convert SF3000 music files named 'foo', 'bar' and 'baz' to ProTracker module files named 'foo/mod', 'bar/mod' and 'baz/mod':
*SF3KtoObj -batch <Star3000$Dir>.Samples foo bar baz
(If the program were correctly ported to a Unix-like system then the output file names would instead be 'foo.mod', 'bar.mod' and 'baz.mod'.)
SF3000 music files do not incorporate a song name.
By default, the name written in the ProTracker module is the leaf of the input file path (e.g. 'BonusLevel' if the input file path was '<Star3000$Dir>.Music.BonusLevel'). If input was read from the standard input stream then the default song name is instead 'Star Fighter 3000'.
If the switch '-name' is used then the following argument specifies an alternative song name, which is truncated to 19 characters if necessary.
If either of the switches '-verbose' and '-debug' is used then the program emits information about its internal operation on the standard output stream. However, this makes it slower and prevents output being piped to another program.
When debugging output is enabled, you must specify an output file name. This is to prevent the ProTracker module being sent to the standard output stream and becoming mixed up with the diagnostic information.
Early versions of the 'SFX_Handler' module automatically blocked sound effects whilst playing music. That distinction was made on the basis of the sample type; sample numbers 0 to 11 are classified as effects whereas 12 to 22 are classified as instruments (surprisingly, 'Radio' is included in the latter category).
This restriction was removed in version 2.10 of 'SFX_Handler' (distributed with release 2.02 of the game), because it didn't make any sense in the context of a configurable number of channels (only 4 of which are used for music). Doing so revealed hitherto inaudible parts of the 'Intro1' music - notes played using the 'Wind' and 'TextBeep' samples. The extra notes were stripped out prior to release 2.04 of the game, to restore the track's original ambience.
The samples index file ('-indexfile' switch) specifies the type of each sample. The command line switch '-allowsfx' has been provided to allow inclusion in the output file of notes played using samples designated as sound effects. By default, such notes are stripped out. This option is only likely to be useful if you have access to music files from an older version of SF3000.
Like most tracker music players, 'SFX_Handler' stops abruptly upon reaching the last division of the pattern that was played at the final song position. It cuts off any notes that are still playing, instead of allowing the samples to finish playing (and perhaps repeat).
This policy means that notes triggered late in the final pattern won't actually be audible! For example, the final division of the last pattern of the 'GameOver' music contains commands to play the 'String' sample at low pitch on channels 0 and 2. These notes would round the tune off nicely, but they are never heard in the game.
If the command line switch '-blankend' is specified then an additional 'blank' pattern will be created in the output file and the play order modified so that this extra pattern is played last, thus allowing late notes to be heard. If the pattern played immediately beforehand contains glissando effects (not yet overridden by new notes on the same channel) then the so-called 'blank' pattern may actually contain Tone Portamento commands to ensure that these glissandos reach their target pitch.
An idiosyncrasy of 'SFX_Handler' is that glissando effects
are applied to all channels playing the sample mapped to the
voice number specified by bits 16-19 of the channel data. In
other words, if two channels are playing the same sample then
a glissando effect for that sample number will cause their
pitches to converge on a common value. The reason is that
glissandos are implemented using the SFX_Pitch
SWI, which doesn't take a channel number as a parameter
(unlike SFX_Force
, which is used to play notes).
The command line switch '-channelglissando' can be used to restrict glissando effects to the channel on which the command was issued. The difference between the two modes of conversion is most obvious with the 'Intro1' music, where the final high note played on channel 4 is either held or else slides towards the same target pitch as a note on channel 3.
In a ProTracker module, glissando effects must be explicitly continued by a series of Tone Portamento commands throughout their expected duration, whereas 'SFX_Handler' continues to update the pitch of a note automatically until its target pitch is reached or it is usurped by another note on the same channel. That makes conversion between the two formats more awkward.
Each Tone Portamento command incorporates a value to govern the pitch slide speed. Even the minimum speed of '1' is noticeably faster than the rate of change when playing music through the 'SFX_Handler' module. (In early versions of 'SFX_Handler', the increment in the phase accumulator pitch oscillator value was updated at the start of alternate buffer fills, which meant the slide speed was dependent upon the configured buffer size!)
Version 0.01 of this converter recognised a '-fastglissando' switch to output contiguous Tone Portmento commands instead of interleaving Tone Portamento commands with Normal Play commands. 'Fast' glissandos are now the only output mode supported. A bug in the versions of 'SFX_Handler' supplied with releases 2.02 to 3.08 (inclusive) meant that glissandos were slower than the original sound player with the default DMA buffer size.
The standard ProTracker pitch range is 3 octaves, whereas Star Fighter 3000's music format allows a range of 8 octaves (because 3 bits of channel data are allocated for the octave number).
After applying the tuning values to the default set of SF3000 samples, it can be heard that octave numbers in a SF3000 music track are exactly one higher than in a ProTracker module. However, some of the tuning values are very large: 'String', 'BassHeavy', 'DrumHeavy' and 'HiHat' are tuned up by at least one octave and 'Piano' is tuned down by nearly a whole octave!
The following table shows the range of octave numbers actually used by each of the music tracks supplied with Star Fighter 3000:
Track name |
Untuned
Min |
Untuned
Max |
Tuned
Min |
Tuned
Max |
ProTracker
Min |
ProTracker
Max |
---|---|---|---|---|---|---|
BonusLevel | 2 | 5 | 2 | 4 | 1 | 3 |
FlightDem1 | 2 | 4 | 2 | 4 | 1 | 3 |
FlightDem2 | 2 | 6 | 3 | 5 | 2 | 4* |
GameOver | 1 | 3 | 1 | 3 | 0* | 2 |
GameStart | 2 | 3 | 2 | 4 | 1 | 3 |
HighScore | 2 | 5 | 2 | 5 | 1 | 4* |
Intro1 | 1 | 4 | 1 | 4 | 0* | 3 |
MissionCom | 2 | 5 | 2 | 4 | 1 | 3 |
Toccatta | 1 | 5 | 1 | 5 | 0* | 4* |
TopScore | 1 | 6 | 1 | 5 | 0* | 4* |
It can be seen that 'GameOver', 'Intro1', 'Toccatta' and 'TopScore' contain notes which are too low to be represented within the standard ProTracker octave range 1 to 3. Conversely, 'FlightDem2', 'HighScore', 'Tocatta', and 'TopScore' contain notes that are too high - even after certain samples have been tuned down.
The default solution adopted by 'SF3KtoProT' is to pre-tune certain ProTracker samples to a higher or lower octave than the original audio data. Hence, the output file may contain several different samples generated from the same source (e.g. 'TopScore/mod' contains samples named 'BassLight-R0-O0' and 'BassLight-R0-O-1' - the latter specifically for low notes).
Andrew Scott gives a table of period values for a range of five octaves rather than the standard three. However, this comes with the caveat that octaves 0 and 4 are non-standard, unlike octaves 1 to 3. Some trackers may be unable to play notes which use those periods, or might even crash! However, Andre Timmermans's 'TimPlayer' module (for RISC OS) seems to cope.
The command line switch '-extraoctaves' has been provided to enable use of these non-standard period values in preference to generating alternative versions of samples pre-tuned to a higher or lower octave. (The conversion routine falls back to generating pre-tuned samples for notes that would be more than one octave outside the standard range.)
Firstly, the sample definitions are read from the index file. Every sound sample file named in the index is opened temporarily to determine its length (which relies on being able to seek the end of the input stream) and then closed again.
The SF3000 music track to be converted to ProTracker format is loaded into memory and then converted in two passes:
The purpose of the first pass is merely to determine which samples (and variants thereof) need to be included in the ProTracker module. Only commands to play notes are examined; glissandos are ignored, as are any notes played using samples designated as sound effects (unless '-allowsfx' was specified).
For each play note command, the sample's tuning value is converted to the nearest whole semitone and used to adjust the octave and note numbers. At this stage it becomes clear whether or not the final octave number will be within the standard ProTracker range (or extended range, if '-extraoctaves' was specified), and hence whether a version of the sample pre-tuned to a higher or lower octave will be required.
Because the ProTracker format does not provide any facility to loop a sample a specific number of times (unlike 'SFX_Handler'), a separate version of each sample will be needed for every distinct number of repeats.
If creation of a ProTracker sample with the required number of repeats and level of pre-tuning has not already been scheduled then a new entry is added to the list of ProTracker samples to be created. This list is later used to write the sample information table at the head of the output file.
The purpose of second pass is to transcode the pattern data from SF3000 to ProTracker module format.
To generate glissando effects, the transcode routine must keep track of which sample (if any) is believed to be playing on each channel, and the target pitch if a glissando is affecting that channel. This record is reset before transcoding each pattern - which isn't foolproof, but is the best that can be done given that patterns may be played in any order.
Each individual division of every pattern is also examined in two passes in order to ensure that glissando effects are applied consistently across all four channels (unless '-channelglissando' was specified):
The first pass discovers any glissando effects and updates the virtual channel state accordingly. The octave and note numbers which specify the target pitch are converted to their ProTracker equivalents using the same technique as before. However, this time the ProTracker sample has already been chosen for each channel and the transcode routine must compensate for the fact that different variants of the same basic sample (all affected by a glissando effect) may have been pre-tuned to different octaves. The final target octave for some channels may be outside the valid range, but nothing can be done except outputting a warning and substituting a nearer octave.
The second pass actually writes the appropriate ProTracker commands for the division being transcoded: a Tone Portamento or Normal Play command if there is no note play command in the SF3000 music data (or the sample number is undefined); otherwise a Set Volume command to play the specified note. In the former case, the virtual channels state is consulted to determine whether a glissando is in progress, and to ensure that only the first Tone Portamento command in the sequence specifies the sample number and target pitch.
Immediately after transcoding the pattern to be played last (as specified by the play order), a snapshot of the virtual channels state is taken to allow continuation of any glissando effects on the additional 'blank' pattern (if one is to be appended).
Finally, the list of ProTracker samples awaiting creation is used to copy audio data from the relevant files into the output file. Because the format of the source data is 16 bit, whereas it is 8 bit in a ProTracker module, the least significant bytes are discarded (the first of each pair, because the data is little-endian).
If the number of repeats for a sample is greater than 0 and less than 15 then the audio data between the repeat offset and the end of the file will be duplicated the requisite number of times. It is expedient to treat 15 as 'loop forever', because that is the only kind of repeats supported by the ProTracker format, and this keeps the output file size reasonable.
Some of the ProTracker samples may need to be pre-tuned to a higher or lower octave than the original audio data. That is done crudely by doubling (or quadrupling) each sample value to lower the pitch by one (or two) octaves. Alternatively it skips one of every two (or three out of four) sample values to raise the pitch by one (or two) octaves.
The set of sound samples to be used when transcoding music to ProTracker format is defined by an index file in plain ASCII text format. This file also defines items of metadata related to each sample.
Each line of text is either a comment (preceded by '#', which must be the first character on that line), a blank line (which consists of nothing but whitespace), or a sample definition (which may have leading and/or trailing whitespace). Sample definitions consist of a numeric ID to be assigned to the sample, the name of a file from which to read raw sample data, an offset from which to repeat the sample (for sustained notes), the type of sample (music or effect), and a tuning value to correct the pitch when playing music.
Sample numbers must lie within the range 0-255, because of the voice table format in a SF3000 music track. The range of sample numbers assigned by a sample index file needn't be contiguous, nor do the samples need to be defined to be ascending numeric order. Any sample numbers which are still undefined when transcoding music will merely cause warning messages. However, the sample index file parser does fault attempts to assign the same sample number more than once.
The repeat offset must be less than the length of the sample data, when both have been rounded down to the nearest even number (the ProTracker module format isn't capable of representing odd sample lengths). Remember that the repeat offset is the number of sample values to skip, whereas the file size is in bytes (each 16 bit sample occupies two bytes).
The sample type is represented by a single letter which may be either upper or lower case: "M" for music or "E" for effect. The significance of the sample type is explained in the section on sound effects.
The magnitude of the tuning value must be small enough that the calculation to convert it to ProTracker tuning units does not overflow a 'long' integer. On RISC OS, the largest value representable by a 'long' integer is one less than 2 to the power of 31, which means that tuning values must lie within the range -22369599, 22369599 (1048575 octaves).
The grammar of a samples index file is as follows (in Backus-Naur Form):
<file> ::= { <line> }* <line> ::= <comment> | <noncomment> <comment> ::= '#' { <comchar> }* <eol> <noncomment> ::= <whitespace> [ <integer> <whitespace> <filename> <whitespace> <integer> <whitespace> <type> <whitespace> <tuning> <whitespace> ] <eol> <filename> ::= <fnchar> { <fnchar> }* <type> ::= "E" | "e" | "M" | "m" <tuning> ::= [ "-" ] <integer> <comchar> ::= any character except <eol> <fnchar> ::= any character except <eol> or <schar> <whitespace> ::= <schar> { <schar> }* <schar> ::= " " | <tab> | <vtab> | <formfeed> <tab> ::= character 9 <eol> ::= character 13 <vtab> ::= character 11 <formfeed> ::= character 12 <integer> ::= <digit> { <digit> }* <digit> ::= "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
Note that <fnchar> must also be a valid character for use in a file name on the host platform. On RISC OS, FileCore-based filing systems such as ADFS reserve the following characters for wildcards and other special uses: '*', '#', '$', '@', '^', '%' and '\'.
read_int32le
function definition
from c.platform to c.decomp because the implementation is
platform-agnostic.
strerror
to
add detail to file access error messages.
isspace
for
better recognition of lines consisting only of whitespace
in a sound samples index file.
fread
and fwrite
instead of
fgetc
and fputc
.
is_switch
function can be found in CBUtilLib
therefore a local version of it was deleted.
Source code is only supplied for the command-line program. To compile and link the code you will also require an ISO 9899:1999 standard 'C' library and three of my own libraries: CBUtilLib, StreamLib and GKeyLib.
Two make files are supplied:
The APCS variant specified for the Norcroft compiler is 32 bit for compatibility with ARMv5 and fpe2 for compatibility with older versions of the floating point emulator. Generation of unaligned data loads/stores is disabled for compatibility with ARMv6. When building the code for release, it is linked with RISCOS Ltd's generic C library stubs ('StubsG').
Before compiling the program for other platforms, rename the
C source and header files with .c and .h file extensions then
move them out of their respective subdirectories. The only
platform-specific code is in filetype.c: the
set_file_type
function. The implementation provided
simply sets the RISC OS file type of the output file; it
could safely be defined as a no-op.
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public Licence as published by the Free Software Foundation; either version 2 of the Licence, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public Licence for more details.
You should have received a copy of the GNU General Public Licence along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
SF3KtoProT was designed and programmed by Christopher Bazley with additional ideas, testing and suggestions by Martin Bazley.
Credit goes to David O'Shea and Keith McKillop for working out the Fednet compression algorithm, although this program no longer incorporates code derived from the DeComp module that David wrote for the Stunt Racer 2000 track designer.
Most of my information on the Amiga ProTracker module format came from a document relating to Digital Symphony, a multi-tasking sound tracker editor for RISC OS which was marketed by Oregan Developments. That description is © 1992/1996 Bernard Jungen and Gil Damoiseaux (members of BASS).
I gleaned additional information from Andrew Scott's Noisetracker/Soundtracker/Protracker module format specification (with credit to Lars Hamre, Norman Lin, Mark Cox, Peter Hanning, Steinar Midtskogen, Marc Espie and Thomas Meyer). That document is available here:
The game Star Fighter 3000 is © FEDNET Software 1994, 1995. Sound & music for the game was by A. M. Perrins.