PSC files, FONTCONV and SCORE character width

Jan de Kloe, August 2002, updated November 15, 2011


Recently, a request was addressed to me for the explanation of the PSC file structure which I had published in February 2002 on the SCORE forum. The text has been slightly edited.


SCORE needs to compute the width of text when it wants to center or justify it. Also it needs to know the length of a syllable when dashes must be centered in lyrics. The information on character widths is kept in FMnn.PSC files which reside in the LIB directory.

FM stands for font metrics, nn is the number of the font which you see in Code16 items as _nn or __nn. Also, this number may be used in Code10 items, Par7, the default being 00 for Times Roman.

Note that the font prefix in Code16 items is not required – it will take a default as well (Text uses the font from the previous text item on EPS generation, if there is none it assumes Times Roman. Note that ordering items can influence this so it not suggested to omit the font prefix. When entering lyrics, the font of the previous syllable is copied immediately). PSC probably stands for Points in SCORE. The standards 35 fonts that come with SCORE have the PSC files FM00.PSC to FM34.PSC.

Other fonts than the standard 35

When you want another font than the ones provided with SCORE you can, but you need to construct a PSC file for that font so that SCORE has detailed information on each character in the set. SCORE provides a utility for making PSC files which is called FONTCONV.EXE.

FONTCONV and points

As input, FONTCONV takes an AFM file and for demonstration’s sake we will use LAUSANNE.AFM. (Note that non-standard fonts requires that your printer recognizes them as firmware or downloaded). AFM stands for Adobe Font Metrics. You can display an AFM file with Notepad, Wordpad or any text processor since it is a plain text file.

In the AFM file are many details on the character set. For each character there is a line which looks like this:

           C 48 ; WX 556 ; N zero ; B 38 -18 519 704 ;

It means that the character with the internal value of 48 (C-field) is 556 (WX-field) points wide.
Since Tom Brodhead’s exposé we all know now what a point is for SCORE (almost the same as a point used in the printing industry). The N-field tells us that this is the character for ‘zero’ but this is comment only. The B-field is not of interest to us as it is information not used by FONTCONV.

FONTCONV only uses the C- and the WX-fields from the AFM file to construct a PSC file. There is one more thing used from this file – the font name. It comes from one of the header records in the AFM file, in our case:

          FontName Lausanne

Note that this name is truncated to 28 character if longer. SCORE needs this name to pass it on to the EPS file.

The PSC file structure

PSC files have a format which does not allow it to be listed with any of the above mentioned utilities and I used a hexadecimal dump program to analyze it. All PSC files have the same length of 694 bytes and the format, like that of DRW files is known as doubly linked list. This format dates from the days that computers had much smaller memories than today’s machine and the file had to be read in pieces. Today we would select a different format if we had to design the PSC file. This is the structure of the first record (length 130 bytes):

byte  contents
    1   hex 4B decimal 75 indicates the recording format (probably)
    2   hex 81 decimal 129 indicates how many bytes of data follow including myself
    3   28 bytes containing the font name, space padded
  31   100 bytes representing 50 integers with character width info
Byte 1 and 2 are the record header. There are five more records with just integers in the file with record headers at byte 133, 263, 363, 493 and 623. At the end of the file, there is another record header without data. This means the records have 64, 49, 64, 64, and 35 integers, including the first 50 bringing the total of integers (widths) to 326.

Why are these records of different length? The reason can only be historic. In the early days, SCORE must have had a limited character set and 50 + 64 + 49 = 163 was probably the maximum of characters it supported. When more characters were added, FONTCONV was modified by just adding records until what it supports today: 326 characters, in theory.

In theory because not all characters are used in all character sets.

The format of an integer, or halfword as I like to call it, is best demonstrated by taking the first integer from our LAUSANNE.PSC which is hex 2C02. This means hex 2c (decimal 44) plus hex 02 (decimal 2) times 256. The high order byte is on the right in the Intel architecture, unlike humans who put the high order digits at the left since the Arabs invented our number system.


This 556 is the width in points for the first character in the table. Here follows the beginning of the PSC table for Lausanne:

address contents
     1        556
     2        556
     3        556
     4        556
     5        556
     6        556
     7        556
     8        556
     9        556
   10        556
   11        667
   12        667
   13        722
   14        722
   15        667
Thus we have 326 values or character widths, one for each character. SCORE looks up the width for each character in this table but this is, again for historic reasons, not a straightforward process.

Two phase table lookup

Logically one would expect that character ‘zero’, our example’s 48 would point to the 48th entry in the table to find 556. In stead there is another translation done by FONTCONV, probably because the originator initially used internal character values as they were used by another architecture than Intel’s. Anyway, it turned out to be necessary to do some reverse engineering and look at FONTCONV from the inside. In it is a table (for those who want to take a look, it is at hex A14A) which translates the AFM C-field to the address in our PSC table. The beginning of the equivalence is:

byte      contents in decimal
     0      112
     1      97
     2      99
     3      101
     32      1
     33      2
     34      3
     35      4
With this the circle is closed. Take our ‘zero’ with internal value 48. First we subtract 16, apparently there is no provision for characters with values 0 through 15 (?). 48-16=32. We look in the equivalence table at displacement 32 and find 1. This 1 is then used as an index to the PSC table and there is where we find 556.


This information is now shared with all members of the SCORE forum. If someone is interested in the translation routines I have developed for the PSC interpretation, just ask (source only, VB6, includes the equivalence table).

The following persons are herewith thanked for their contribution: Paul Terry and Matanya Ophee for pointing out the function of the AFM file and its relation to PSC; Andrew Parker for suggesting to share my knowledge of SCORE internals with the forum; Krzysztof Rogalski for supplying the file LAUSANNE.AFM; Tom Brodhead for letting me refer to his points explanation; and of course Leland Smith because I peaked into FONTCONV.EXE.

Following publication of this text on the forum, Chanvrelin and Tom Owen ("I am using this technique for proper centering of punctuated lyrics") suggested to manipulate PSC files to influence placement of dashes between lyrics. Do not modify a standard PSC file but rather copy one to an unused number (FM36.PSC – FM89.PSC) which is then manipulated to define a zero length for punctuation characters.

This study was performed as part of the development of SipSib, the Sibelius EPS to SCORE converter.