485 lines
18 KiB
HTML
485 lines
18 KiB
HTML
<html>
|
|
<head>
|
|
<title>CD+G Revealed</title>
|
|
<meta name="description" content="An informal description of how CD+G works.">
|
|
<meta name="keywords" content="Jim Bumgardner, karaoke, CD+G, yellow book, red book, subchannel, compact disc">
|
|
<link rel=stylesheet type="text/css" href="base_sm.css">
|
|
</head>
|
|
<body BGCOLOR=white TEXT=black>
|
|
|
|
<table width=100% cellpadding=0 cellspacing=0 border=0 bgcolor=#99AABB>
|
|
<tr>
|
|
<td width=60><img src="/img/dot.gif" width=60 height=60></td>
|
|
<td width=97>
|
|
<a href="/" title="See who put together this foolishness"><img align=center valign=middle border=0 width=130 height=48 src="/img/jbum_title.gif" border=0></a>
|
|
</td>
|
|
<td width=32><img src="/img/dot.gif" width=102 height=60></td>
|
|
<td align=right>
|
|
<table cellpadding=0 cellspacing=0 border=0><tr><td>
|
|
<font size=2>
|
|
<a href="/" title="Current Events in the land of jbum">Home</a> |
|
|
<a href="/egocentrism.html" title="Biography, Resume, Interviews, Hero Worship">About Me</a> |
|
|
<a href="/funstuff.html" title="Diversions, Magic Tricks, Novelties">Fun Stuff</a> |
|
|
<a href="/flashstuff.html" title="Flash">Flash</a> |
|
|
<a href="/palacestuff.html" title="All things Palace-related">Palace Stuff</a>
|
|
<br>
|
|
<a href="/kaleidoscopes.html" title="Kaleidoscopes">Kaleidoscopes</a> |
|
|
<a href="/software.html" title="Free PC and Mac Software by jbum">Free Software</a> |
|
|
<a href="/links.html" title="The obligatory links page">Links</a>
|
|
</font>
|
|
</td></tr></table>
|
|
</td>
|
|
<td width=60><img src="/img/dot.gif" width=60 height=60></td>
|
|
</tr></table>
|
|
|
|
|
|
<table width=100% border=0 cellpadding=0 cellspacing=0>
|
|
<tr>
|
|
<td width=60> </td>
|
|
<td width="5%"> </td>
|
|
<td width=90% valign=top>
|
|
|
|
<br>
|
|
|
|
|
|
|
|
4/2005: <a href="http://www.geocities.com/mixage/">Bruno Di Gleria</a> has developed a Karaoke player for Macintosh called <a href="http://www.geocities.com/mixage/">QMidi</a>, which
|
|
supports CD+G playback, among other things.
|
|
<P>
|
|
7/2004: David Cotter is working on an <a href="http://www.lazilong.com/ktunes/">OS X compatible CD+G Player, called KTunes</a>, which incorporates
|
|
some of my old source code. <a href="http://www.lazilong.com/ktunes/">Check it out!</a>
|
|
<p>
|
|
<hr>
|
|
<p>
|
|
<font size=+2><b>CD+G Revealed: Playing back Karaoke tracks in Software</b></font>
|
|
<p>
|
|
Version 1.0
|
|
<p>
|
|
1/9/95
|
|
<p>
|
|
Jim Bumgardner
|
|
<p>
|
|
<h2>Introduction</h2>
|
|
<p>
|
|
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).
|
|
<p>
|
|
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.
|
|
<p>
|
|
<pre>
|
|
|
|
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 *
|
|
</pre>
|
|
|
|
</td>
|
|
<td width=20> </td>
|
|
<td width=120 valign=top bgcolor="#99AABB">
|
|
<script type="text/javascript"><!--
|
|
google_ad_client = "pub-1449267043676994";
|
|
google_ad_width = 120;
|
|
google_ad_height = 600;
|
|
google_ad_format = "120x600_as";
|
|
google_ad_channel ="9492053763";
|
|
google_color_border = "99AABB";
|
|
google_color_bg = "99AABB";
|
|
google_color_link = "0000CC";
|
|
google_color_url = "008000";
|
|
google_color_text = "000000";
|
|
// google_page_url = "http://www.jbum.com/donate/";
|
|
//--></script>
|
|
<script type="text/javascript"
|
|
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
|
|
</script>
|
|
</td>
|
|
</table>
|
|
|
|
|
|
|
|
</body> </html>
|