Skip to content

Commit

Permalink
Handle Uint8Array creation; pass single packets to CDGInstructions
Browse files Browse the repository at this point in the history
  • Loading branch information
bhj committed Jan 16, 2021
1 parent 506603a commit bc557ff
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 48 deletions.
12 changes: 5 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,23 +39,21 @@ const cdg = new CDGraphics(canvas, { forceKey: true }) // force background trans
| shadowOffsetX | number | [CanvasRenderingContext2D.shadowOffsetX](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/shadowOffsetX) | `0` |
| shadowOffsetY | number | [CanvasRenderingContext2D.shadowOffsetY](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/shadowOffsetY) | `0` |

**Note:** When using shadow* options, graphics will render smaller and/or offset to fit the canvas as needed to avoid clipping the shadow.
**Note:** When using shadow* options, graphics may render smaller and/or offset to fit the canvas as needed to avoid clipping the shadow.

### `.load(array)`
### `.load(buffer)`

Loads an array of bytes and parses the CD+G instructions. This must be done before calling `render()`.
Loads a CD+G file. Expects an [ArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer), which can be had via the [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response) of a [fetch()](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API).

```js
fetch(cdgFileUrl)
.then(response => response.arrayBuffer())
.then(buffer => {
cdg.load(new Uint8Array(buffer))
})
.then(buffer => cdg.load(buffer))
```

### `.render([number])`

Renders the frame at the given playback position (in seconds). Calling without a parameter will re-paint the last-rendered frame to the canvas.
Renders the frame at the given playback position (in seconds). Calling without a parameter will re-paint the last-rendered frame to the canvas. You must `load()` a CD+G file (see above) before calling `render()`.

This method is designed to be used with [requestAnimationFrame](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame) and the [currentTime](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/audio#attr-currentTime) property of an HTMLMediaElement (usually an `<audio>` element). The following excerpt shows a basic render loop:

Expand Down
7 changes: 2 additions & 5 deletions demo/demo.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,7 @@ document.addEventListener('DOMContentLoaded', () => {
fetch(cdgUrl)
.then(response => response.arrayBuffer())
.then(buffer => {
// arrayBuffer to Uint8Array
cdg.load(new Uint8Array(buffer))

// start loading audio
audio.src = audioUrl
cdg.load(buffer)
audio.src = audioUrl // pre-load audio
})
})
69 changes: 33 additions & 36 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,8 +132,8 @@ CDGContext.prototype.TILE_WIDTH = 6
CDGContext.prototype.TILE_HEIGHT = 12

class CDGInstruction {
constructor (bytes = [], offset = 0) {
this.bytes = bytes.slice(offset, offset + PACKET_SIZE)
constructor (bytes) {
this.bytes = bytes
}

execute (context) { }
Expand All @@ -156,12 +156,11 @@ class CDGNoopInstruction {
*
************************************************/
class CDGMemoryPresetInstruction extends CDGInstruction {
constructor (bytes, offset) {
super(bytes, offset)
constructor (bytes) {
super(bytes)

const doff = offset + CDG_DATA
this.color = bytes[doff] & 0x0F
this.repeat = bytes[doff + 1] & 0x0F
this.color = bytes[CDG_DATA] & 0x0F
this.repeat = bytes[CDG_DATA + 1] & 0x0F
}

execute (context) {
Expand All @@ -176,10 +175,10 @@ class CDGMemoryPresetInstruction extends CDGInstruction {
*
************************************************/
class CDGBorderPresetInstruction extends CDGInstruction {
constructor (bytes, offset) {
super(bytes, offset)
constructor (bytes) {
super(bytes)

this.color = bytes[offset + CDG_DATA] & 0x0F
this.color = bytes[CDG_DATA] & 0x0F
}

execute ({ DISPLAY_BOUNDS, WIDTH, pixels, HEIGHT }) {
Expand Down Expand Up @@ -209,15 +208,14 @@ class CDGBorderPresetInstruction extends CDGInstruction {
*
************************************************/
class CDGTileBlockInstruction extends CDGInstruction {
constructor (bytes, offset) {
super(bytes, offset)
constructor (bytes) {
super(bytes)

const doff = offset + CDG_DATA
// some players check bytes[doff+1] & 0x20 and ignores if it is set (?)
this.colors = [bytes[doff] & 0x0F, bytes[doff + 1] & 0x0F]
this.row = bytes[doff + 2] & 0x1F
this.column = bytes[doff + 3] & 0x3F
this.pixels = bytes.slice(doff + 4, doff + 16)
this.colors = [bytes[CDG_DATA] & 0x0F, bytes[CDG_DATA + 1] & 0x0F]
this.row = bytes[CDG_DATA + 2] & 0x1F
this.column = bytes[CDG_DATA + 3] & 0x3F
this.pixels = bytes.slice(CDG_DATA + 4, CDG_DATA + 16)
}

execute (context) {
Expand Down Expand Up @@ -262,17 +260,16 @@ class CDGTileBlockXORInstruction extends CDGTileBlockInstruction {
*
************************************************/
class CDGScrollPresetInstruction extends CDGInstruction {
constructor (bytes, offset) {
super(bytes, offset)
constructor (bytes) {
super(bytes)

const doff = offset + CDG_DATA
this.color = bytes[doff] & 0x0F
this.color = bytes[CDG_DATA] & 0x0F

const hScroll = bytes[doff + 1] & 0x3F
const hScroll = bytes[CDG_DATA + 1] & 0x3F
this.hCmd = (hScroll & 0x30) >> 4
this.hOffset = (hScroll & 0x07)

const vScroll = bytes[doff + 2] & 0x3F
const vScroll = bytes[CDG_DATA + 2] & 0x3F
this.vCmd = (vScroll & 0x30) >> 4
this.vOffset = (vScroll & 0x07)
}
Expand Down Expand Up @@ -341,9 +338,9 @@ class CDGScrollCopyInstruction extends CDGScrollPresetInstruction {
*
************************************************/
class CDGSetKeyColorInstruction extends CDGInstruction {
constructor (bytes, offset) {
super(bytes, offset)
this.index = bytes[offset + CDG_DATA] & 0x0F
constructor (bytes) {
super(bytes)
this.index = bytes[CDG_DATA] & 0x0F
}

execute (context) {
Expand All @@ -357,14 +354,13 @@ class CDGSetKeyColorInstruction extends CDGInstruction {
*
************************************************/
class CDGLoadCLUTLowInstruction extends CDGInstruction {
constructor (bytes, offset) {
super(bytes, offset)
constructor (bytes) {
super(bytes)

const doff = offset + CDG_DATA
this.colors = Array(8)

for (let i = 0; i < 8; i++) {
const cur = doff + 2 * i
const cur = CDG_DATA + 2 * i

let color = (bytes[cur] & 0x3F) << 6
color += bytes[cur + 1] & 0x3F
Expand Down Expand Up @@ -404,16 +400,16 @@ class CDGLoadCLUTHighInstruction extends CDGLoadCLUTLowInstruction {
*
************************************************/
class CDGParser {
static parseOne (bytes, offset) {
const command = bytes[offset] & this.COMMAND_MASK
static parse (bytes) {
const command = bytes[0] & this.COMMAND_MASK

/* if this packet is a cdg command */
if (command === this.CDG_COMMAND) {
const opcode = bytes[offset + 1] & this.COMMAND_MASK
const opcode = bytes[1] & this.COMMAND_MASK
const InstructionType = this.BY_TYPE[opcode]

if (typeof (InstructionType) !== 'undefined') {
return new InstructionType(bytes, offset)
return new InstructionType(bytes)
} else {
console.log(`Unknown CDG instruction (instruction = ${opcode})`)
return new CDGNoopInstruction()
Expand Down Expand Up @@ -461,11 +457,12 @@ class CDGPlayer {
this.pc = -1
}

load (bytes) {
load (buffer) {
this.init()
const bytes = new Uint8Array(buffer)

for (let offset = 0; offset < bytes.length; offset += PACKET_SIZE) {
const instruction = CDGParser.parseOne(bytes, offset)
const instruction = CDGParser.parse(bytes.slice(offset, offset + PACKET_SIZE))
if (instruction != null) this.instructions.push(instruction)
}
}
Expand Down

0 comments on commit bc557ff

Please sign in to comment.