-
Notifications
You must be signed in to change notification settings - Fork 0
/
cdg.h
279 lines (244 loc) · 8.92 KB
/
cdg.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
//***************************************************************************
//
// File: cdg.h
//
// Author: Isaac Brodsky
//
// Project: CD+G Deck
//
// Version: 1.0.3
//
// Date: 2012 AUGUST 6
// 2012 OCTOBER 16
// 2012 OCTOBER 29
//
// COPYRIGHT 2012 Isaac Brodsky ALL RIGHTS RESERVED.
//
// Compact disc subcode graphics decoder, definition.
//
// Compact disc subcode graphics (CD + Graphics, CD+G, subcode graphics)
// are simple graphics programs that can be embedded on audio CDs. Audio
// CDs contain subcode information interspersed along with the audio
// tracks. Normally only timing and seek information is stored in the
// subcodes, but with the extensions to the standard in IEC 60908 (2ed)
// graphics programs can be stored as well.
//
// This is a decoder from CD+G subcodes to displayable graphics.
//
// Information about this format can be found in IEC 60908 2ed.
// Some (limited) information available online at:
// http://jbum.com/cdg_revealed.html
//
//***************************************************************************
#ifndef CDG_H
#define CDG_H
#include <iostream>
using namespace std;
#include <stdint.h>
//***************************************************************************
// Constants and compilation options.
//***************************************************************************
#define SHRINK_CDG // use space saving memory layout.
// MSVC seems to have trouble
// without this. (but only sometimes?)
#define BYTES_PER_SECOND (96 * 75) // number of bytes of subcode information
// per second of audio.
#define CDG_NUM_COLORS 16
#define CDG_NUM_COLOR_CHANNELS 4
#define CDG_WIDTH 300 // size in pixels
#define CDG_HEIGHT 216 //
#define ROW_MULT 12 // Size of each discrete block ("font")
#define COL_MULT 6 // of CDG data.
// Bit masks
#define LOWER_6_BITS 0x3F // 63
#define LOWER_5_BITS 0x1F // (LOWER_6_BITS >> 1)
#define LOWER_4_BITS 0x0F // (LOWER_6_BITS >> 2)
#define LOWER_3_BITS 0x07 // (LOWER_6_BITS >> 3)
#define LOWER_2_BITS 0x03 // (LOWER_6_BITS >> 4)
//***************************************************************************
// Represents the mode a seek operation will use.
//
// S_ENHANCED will cause the seek system to process the file up to the seek
// location. This will result in technically correct seeking but is slower.
//
// S_DIRECT is faster and does not involve processing the file up to the
// given point (VLC uses this type of seeking.) The read pointer is simply
// adjusted to the new location. This may result in some temporary graphical
// corruption.
//***************************************************************************
enum SeekMode
{
SEEK_DIRECT,
SEEK_ENHANCED
};
//***************************************************************************
// Represents possible Subcode commands that this program can process
//
// C++11 features being used here
// http://en.wikipedia.org/wiki/C%2B%2B0x#Strongly_typed_enumerations
// would like to use "enum class" but not supported
//***************************************************************************
enum SubCode_Command : char
{
SCCMD_NONE = 0x00,
SCCMD_CDG = 0x09
};
//***************************************************************************
// This type represents possible CDG command codes.
//***************************************************************************
enum CDG_Instruction : char
{
CDG_MEMORYPRESET = 1,
CDG_BORDERPRESET = 2,
CDG_TILEBLOCK = 6,
CDG_SCROLLPRESET = 20,
CDG_SCROLLCOPY = 24,
CDG_TRANSPARENT = 28,
CDG_LOADCTLOW = 30,
CDG_LOADCTHIGH = 31,
CDG_TILEBLOCKXOR = 38
};
#pragma pack(push, 1) //disable packing since we're reading these
//structs in from disk.
//***************************************************************************
// Structure of the data field in MEMORYPRESET CDG commands.
//***************************************************************************
struct CDG_MemPreset
{
char color;
char repeat; // ignored in this implementation
char padding[14];
};
//***************************************************************************
// Structure of the data field in BORDERPRESET CDG commands.
//***************************************************************************
struct CDG_BorderPreset
{
char color;
char padding[15];
};
//***************************************************************************
// Structure of the data field in FONT, and FONTXOR CDG commands.
//
// Semantics note: I use the terms TILE and FONT commands interchangably.
// Other sources online (probably as a result of the document on jbum.com)
// call these commands "TILE" commands, the spec says "FONT."
//***************************************************************************
struct CDG_Tile
{
char color0; // spec also stores the channel number
char color1; // in these two bytes
char row;
char column;
char tilePixels[12];
};
//***************************************************************************
// Structure of the data field in SCROLLCOPY and SCROLLPRESET CDG commands.
//***************************************************************************
struct CDG_Scroll
{
char color;
char hScroll; // these contain additional data
char vScroll; // embedded in the higher bits
char padding[13];
};
//***************************************************************************
// Structure of the data field in TRANSPARENCY CDG commands.
//
// The transparency feature seems to be a little used one, I've never seen
// a disk with it, and the spec doesn't mention if transparency should be
// reset when LOADCLUT commands are executed.
//
// (The lack of nicer typesetting for the TRANSPARENT diagram in the spec
// is another indicator that this is a little cared for feature.)
//***************************************************************************
struct CDG_Transparent
{
char alphaChannel[16];
};
//***************************************************************************
// Structure of the data field in LOADCLUTHIGH and LOADCLUTLOW CDG commands.
//***************************************************************************
struct CDG_LoadCLUT
{
short colorSpec[8];
};
//***************************************************************************
// Structure of a single CDG command. These are stored four in a packet on
// disk. This subcode data is stored in the R-W subcode channels of digital
// audio CDs.
//
// Only the lower six bits of any byte in this structure should be used, the
// high two bits (if not stripped and zeroed) are the P and Q subcode
// channels which are used for other purposes.
//
// Application should use the appropriate part of the data union based on
// the command and instruction fields.
//***************************************************************************
struct SubCode
{
SubCode_Command command;
CDG_Instruction instruction;
char parityQ[2];
union
{
char data[16];
CDG_MemPreset memDat;
CDG_BorderPreset borderDat;
CDG_Tile tileDat;
CDG_Scroll scrollDat;
CDG_Transparent transparentDat;
CDG_LoadCLUT clutDat;
} data;
char parityP[4];
}; //1 pack, 4 PACKs per PACKET
#pragma pack(pop) // allow default for the classes;
// compiler knows what it's doing.
//***************************************************************************
// Represents a CD+G decoder.
//***************************************************************************
class CDG
{
private:
uint8_t colorTable[CDG_NUM_COLORS][CDG_NUM_COLOR_CHANNELS]; //rgba
#ifdef SHRINK_CDG
uint8_t screen[CDG_WIDTH][CDG_HEIGHT/2]; // use 4 bits per byte per pixel
#else
#error "Non shrunken CDG not a supported feature."
uint8_t screen[CDG_WIDTH][CDG_HEIGHT]; // use all 8 bits per pixel, even though
// each only takes 4
#endif
uint8_t ph, pv;
uint8_t border;
uint8_t channel;
//private functions
static bool readNext(istream &in, SubCode &out);
void swapPixels(int x1, int y1, int x2, int y2);
void rotateV(int cmd);
void rotateH(int cmd);
void loadColor(int idx, short col);
void fillPixels(int x1, int y1, int x2, int y2, uint8_t color);
void putPixel(int x, int y, uint8_t color, bool isXor = false);
void execLoadct(const SubCode&);
void execMemoryPreset(const SubCode&);
void execBorderPreset(const SubCode&);
void execScroll(const SubCode&);
void execTransparent(const SubCode&);
void execTile(const SubCode&);
public:
CDG();
bool operator==(const CDG&) const;
void getColor(uint8_t code, uint8_t &r, uint8_t &g, uint8_t &b, uint8_t &a) const;
uint8_t getPixel(int x, int y) const;
void getPointers(uint8_t &v, uint8_t &h) const;
uint8_t getBorderColor() const;
uint8_t getChannel() const;
void setChannel(uint8_t);
void execNext(const SubCode&);
void execNext(const SubCode&, int&);
int execCount(istream &in, int count, int &dirty);
void seekTo(istream &in, int loc, SeekMode mode);
static int sizeToSeconds(int sz);
static int percentToSecond(double percent, int total);
};
#endif