In the early 1990s, I worked at Warner New Media (which was later merged into Time Warner Interactive), an early producer of discs in the CD+G format. Time/Warner was a Philips licensee and as an employee I had access to the various CD-Audio and CD-ROM standards, including the CD+G standard, which was an extension of the so-called Red Book. At this time (and to this day) the only official source of this information was Philips and you had to pay a very expensive licensing fee (in the $30,000 range as I recall) to get access to it. The price has since been lowered to $100.
At this time, there were no pure software players that could play CD+G (Karaoke) discs on a desktop computer -- you needed a special karaoke player to do it. So, using the Red Book as a reference, I wrote a software player capable of playing these discs on a Macintosh from an Apple CD300 CD-ROM drive (or other drives that supported the same driver calls).
In 1995, I decided to make a technical document describing the CD+G format, so that other hobbyists could reproduce my work without having to pay an exhorbitant fee for the license. To make this document, I used my own source code (and memory) as a reference, and described the CD+G format from the point-of-view of a C programmer attempting to write a player. I also released the source code to my original CD+G player software.
The original document, "CD+G Revealed", is shown below
I remember being a little nervous publishing it, since I thought there might be some threat of a (baseless) lawsuit that I could ill afford, but ultimately nothing transpired.
In the years since, I have been gratified to see my document cited as a useful reference by numerous people who have written Karaoke playback sofware.
Jim Bumgardner 2020-07-09
Version 1.0 1/9/95 Jim Bumgardner Introduction A CD+G is a special Audio Compact disc that contains graphics data in addition to the audio data on the disc. The disc can be played on a regular Audio CD player, but when played on a special CD+G player, can output a graphics signal (typically, the CD+G player is hooked up to a television set). This file describes how CD+G information is stored on the disc, and provides information to help programmers implement CD+G playback on personal computers equipped with CD+G compatible CD-ROM drives. This document assumes a familiarity with computer programming, and especially the C programming language. Ever since I released a utility for the Macintosh that allows owners of Apple's CD300 to play CD+G discs (CDG Player), I have received numerous requests asking for the CD+G specification. Unfortunately, this information has not been made available to the general public (as far as I know) and is hard to find. Hopefully, this informal description will help. It has been a while since I read the CD+G specification. I am describing this system from memory, and will often deviate from the nomenclature used in the actual CD Audio and CD+G specification. How CD+G information is stored on the disc ========================================== A Compact Disc contains two kinds of data: Content data, which is used to store Audio and Computer software and the like, and Subchannel data, which is normally used by the CD player to help control the disc. Assuming the disc is being read at normal speed (approx 150 kps) for audio playback, the data is read at 75 sectors per second. In each sector there are 2352 bytes of Content data and 96 bytes of Subchannel data. On the disc, the Subchannel data is interspersed with the audio data. But when the disc is played back, the two streams of data are separated. On a typical CD-ROM player you can't access the Subchannel information - it is never sent to the computer. In fact, until recently on most CD-ROM players, you couldn't read the Content data on an audio track either. You could only read the Content data a data track which is used specifically for storing computer information. Presumeably, this was done to prevent people from easily pirating Audio CDs. More recently however, manufacturers have started producing drives that allow the computer to access not only the Content data on an audio track, but also the Subchannel data. As we shall see, it is this Subchannel capability which is needed for a computer to be able to play a CD+G disc. The 96 bytes of Subchannel information in each sector contain 4 packets of 24 bytes apiece. The structure of the packet is as follows: typedef struct { char command; char instruction; char parityQ[2]; char data[16]; char parityP[4]; } SubCode; Each byte in the 16 byte SubCode.data[] field can be thought of as being divided into 8-bits. Each of these bits corresponds to a separate stream of information. These streams are called "channels", and are labeled starting with the letter P, like so: Channel# P Q R S T U V W Bit# 7 6 5 4 3 2 1 0 --------------- Byte # 0 0 0 0 0 0 0 0 0 Byte # 1 0 0 0 0 0 0 0 0 Byte # 2 0 0 0 0 0 0 0 0 . . (etc.) . Byte # 15 0 0 0 0 0 0 0 0 Both the P and Q channels, on a regular Audio CD are used for timing information. They are used to assist the CD Player in tracking the current location on the disc, and to provide the timing information for the time display on the CD Player. On a regular Audio CD, channels R through W are unused. The CD+G format takes advantage of the unused channels R thru W. These unused six bits are used to store graphics information. Note that this is an extremely thin stream of information. 6 bits per byte * 16 bytes per packet * 4 packets per sector * 75 sectors per second = 28800 bits per second, or 3.6 K per second. By comparison, a typical 160 x 120 QuickTime movie uses 90K per second. CD+G Graphics Instructions ========================== The CD+G standard is published by Philips and Sony as an extension of the Red Book. It defines a specific system for decoding the subchannels R thru W. Note: if you gain sufficient control of the CD mastering process, you could define your own Audio-compatible format which is potentially more interesting than CD+G. For example, you could use the Subchannel to store control information for an animatronics robot, MIDI information, etc. There already is a CD+G+MIDI extension of the CD+G standard, but I won't describe it here. Also, there is an "Extended" CD+G standard which allows for more colors and effects in a backward compatible manner, but I have yet to see any discs published in this format, so I will only describe the basic format. In the CD+G system, 16 color graphics are displayed on a raster field which is 300 x 216 pixels in size. The middle 294 x 204 area is within the TV's "safe area", and that is where the graphics are displayed. The outer border is set to a solid color. The colors are stored in a 16 entry color lookup table. Each color in the table is drawn from an RGB space of 4096 (4 bits each for R,G and B) colors. Since we are using a 16 color table, each pixel can be stored in 4 bits, resulting in a total pixelmap size of 4 * 300 * 216 = 259200 bits = a little less than 32K. The SubCode.command and SubCode.instruction fields in each SubCode packet are used to determine how the data is to be interpreted. I will enumerate these commands below. When reading the command and instruction fields, you should only pay attention to the lower 6 bits of each of these bytes (e.g. by ANDing the byte with the hex value 3Fh). The upper 2 bits are used for the P and Q channels which you should ignore. If the lower 6 bits of the command field are equal to 9, then the SubCode packet contains CD+G information, otherwise it should be ignored. If the packet contains CD+G information, then you use the instruction field (again, the lower six bits), to determine how to interpret the data. An example will be shown below. Instruction List (Brief) ================ A more detailed description of each instruction appears later in this document. Number Name/Description ====== ================ 1 Memory Preset Set the screen to a particular color. 2 Border Preset Set the border of the screen to a particular color. 6 Tile Block (Normal) Load a 12 x 6, 2 color tile and display it normally. 20 Scroll Preset Scroll the image, filling in the new area with a color. 24 Scroll Copy Scroll the image, rotating the bits back around. 28 Define Transparent Color Define a specific color as being transparent. 30 Load Color Table (entries 0-7) Load in the lower 8 entries of the color table. 31 Load Color Table (entries 8-15) Load in the upper 8 entries of the color table. 38 Tile Block (XOR) Load a 12 x 6, 2 color tile and display it using the XOR method. Code Example =========== This code example shows how you might implement the graphics display dispatcher for a CD+G player in C. #define SC_MASK 0x3F #define SC_CDG_COMMAND 0x09 #define CDG_MEMORYPRESET 1 #define CDG_BORDERPRESET 2 // etc... - define each instruction listed above ReadSubCodePacket(&subCode); if ((subCode.command & SC_MASK) == SC_CDG_COMMAND) { // CD+G? switch (subCode.instruction & SC_MASK) { case CDG_MEMORYPRESET: MemoryPreset(subCode.data); break; case CDG_BORDERPRESET: BorderPreset(subCode.data); break; // etc... - implemement each instruction listed above } } How to read SubCode packets on a Computer equipped with a CD-ROM drive ====================================================================== This is the (possibly) hard part. If your CD-ROM drive doesn't support this feature, you are shit-out-of-luck. If the *Driver* software that is used to control your CD-ROM drive doesn't support this feature, you are also shit-out-of-luck, although less so, since you might be able to write a new driver, or obtain a new one. Good luck. As far as I know, the only way this step can be easily solved (today), it to use an Apple Macintosh equipped with an Apple CD300 drive or better. Both this drive, and the driver that is included with it support SubCode access. Apple publishes a document called "CD-ROM Driver Calls" which is available from ftp.apple.com. It describes the newer driver calls that allow you to retrieve SubCode packets on the Apple CD300 drive. These calls often do not work on 3rd party drives. I used the information in this document to code a function based on the Mac Toolbox call PBControl, which will retrieve SubCode packets. CD+G Instructions (detailed) ================= Here I describe the CD+G instructions in detail, hopefully providing enough information for a programmer to implement CD+G playback. Note that in all these instructions, only the lower 6 bits of each data byte are used. So, for example, If I refer to subCode.data[0], I actually mean (subCode.data[0] & 0x3F). **** Memory Preset (subCode.instruction==1) **** In this instruction, the 16 byte data field is interepreted as follows. typedef struct { char color; // Only lower 4 bits are used, mask with 0x0F char repeat; // Only lower 4 bits are used, mask with 0x0F char filler[14]; } CDG_MemPreset; Color refers to a color to clear the screen to. The entire screen should be cleared to this color. When these commands appear in bunches (to insure that the screen gets cleared), the repeat count is used to number them. If this is true, and you have a reliable data stream, you can ignore the command if repeat != 0. *** Border Preset (subCode.instruction==2) *** In this instruction, the 16 byte data field is interepreted as follows. typedef struct { char color; // Only lower 4 bits are used, mask with 0x0F char filler[15]; } CDG_BorderPreset; Color refers to a color to clear the screen to. The border area of the screen should be cleared to this color. The border area is the area contained with a rectangle defined by (0,0,300,216) minus the interior pixels which are contained within a rectangle defined by (6,12,294,204). *** Tile Block Normal (subCode.instruction==6) Tile Block XOR (subCode.instruction==38) *** These commands load a 12 x 6 tile of pixels from the subCode.data area. I recall that in the original CD+G spec, the tile is refered to as a "font", but I think the word tile is more appropriate, because the tile can (and does) contain any graphical image, not just text. Larger images are built by using multiple tiles. The XOR variant is a special case of the same command, the difference is described below. The tile is stored using 1-bit graphics. The structure contains two colors which are to be used when rendering the tile. The tile is extracted from 16 bytes of subCode.data[] in the following manner: typedef struct { char color0; // Only lower 4 bits are used, mask with 0x0F char color1; // Only lower 4 bits are used, mask with 0x0F char row; // Only lower 5 bits are used, mask with 0x1F char column; // Only lower 6 bits are used, mask with 0x3F char tilePixels[12]; // Only lower 6 bits of each byte are used } CDG_Tile; color0, color1 describe the two colors (from the color table) which are to be used when rendering the tile. Color0 is used for 0 bits, Color1 is used for 1 bits. Row and Column describe the position of the tile in tile coordinate space. To convert to pixels, multiply row by 12, and column by 6. tilePixels[] contains the actual bit values for the tile, six pixels per byte. The uppermost valid bit of each byte (0x20) contains the left-most pixel of each scanline of the tile. In the normal instruction, the corresponding colors from the color table are simply copied to the screen. In the XOR variant, the color values are combined with the color values that are already onscreen using the XOR operator. Since CD+G only allows a maximum of 16 colors, we are XORing the pixel values (0-15) themselves, which correspond to indexes into a color lookup table. We are not XORing the actual R,G,B values. *** Scroll Preset (subCode.instruction==20) Scroll Copy (subCode.instruction==24) *** In these instruction, the 16 byte data field is interepreted as follows. typedef struct { char color; // Only lower 4 bits are used, mask with 0x0F char hScroll; // Only lower 6 bits are used, mask with 0x3F char vScroll; // Only lower 6 bits are used, mask with 0x3F } CDG_Scroll; This command is used to scroll all the pixels on the screen horizontally and/or vertically. The color refers to a fill color to use for the new area uncovered by the scrolling action. It is only used in the Scroll Preset command. In the Scroll Copy command the screen is "rotated" around. For example, in scrolling to the left, pixels uncovered on the right are filled in by the pixels being scrolled off the screen on the left. The hScroll field is a compound field. It can be divided into two fields like so: SCmd = (hScroll & 0x30) >> 4; HOffset = (hScroll & 0x07); SCmd is a scrolliing instruction, which is either 0, 1 or 2. 0 means don't scroll 1 means scroll 6 pixels to the right, 2 means scroll 6 pixels to the left. HOffset is a horizontal offset which is used for offsetting the graphic display by amounts less than 6 pixels. It can assume values from 0 to 5. Similarly, the vScroll field is a compound field. It can be divided into two fields like so: SCmd = (vScroll & 0x30) >> 4; VOffset = (vScroll & 0x0F); SCmd is a scrolliing instruction, which is either 0, 1 or 2. 0 means don't scroll 1 means scroll 12 pixels down, 2 means scroll 12 pixels up. VOffset is a vertical offset which is used for offsetting the graphic display by amounts less than 12 pixels. It can assume values from 0 to 11. Smooth horizontal and vertical scrolling in all directions can be done by combining scroll commands. For example, here is a smooth horizontal scroll to the left: SCmd HScroll === ======= 0 1 0 2 0 3 0 4 0 5 0 6 2 0 (repeat) You can create the effect of an infinite panorama by continually loading in new tiles into the border area and scrolling them into view. *** Define Transparent Color (subCode.instruction==28) *** This command is used to define a CLUT color as being transparent, for example so that the the graphics can be overlayed on top of a live video signal. *** Load Color Table Lo [colors 0 thru 7] (subCode.instruction==30) Load Color Table High [colors 8 thru 15] (subCode.instruction==31) *** These commands are used to load in the colors for the color table. The colors are specified using 4 bits each for R, G and B, resulting in 4096 possible colors. The only different between the two instructions is whether the low part or the high part of the color table is loaded. In these instruction, the 16 byte data field is interpreted as follows. typedef struct { short colorSpec[8]; // AND with 0x3F3F to clear P and Q channel } CDG_LoadCLUT; Each colorSpec value can be converted to RGB using the following diagram: [---high byte---] [---low byte----] 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 X X r r r r g g X X g g b b b b Note that P and Q channel bits need to be masked off (they are marked here with Xs. The Load CLUT commands are often used in CD+G to provide the illusion of animation through the use of color cyling. * End of Document *