Skip to content

Commit ef2bff0

Browse files
committed
Fix to run on node.js
Switch to `@kmamal/sdl`.
1 parent fe89aa3 commit ef2bff0

File tree

11 files changed

+262
-139
lines changed

11 files changed

+262
-139
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,5 @@ typings
1616
/release
1717

1818
/nodejs/nesemu.js
19+
/nodejs/package-lock.json
20+
*.LICENSE.txt

nodejs/.babelrc

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
{
22
"presets": [
3-
["env", {"module": false}]
3+
[
4+
"@babel/preset-env",
5+
{
6+
"useBuiltIns": "usage",
7+
"corejs": 3
8+
}
9+
]
410
]
511
}

nodejs/README.md

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,12 @@ for node.js
33

44
### Requirement
55

6-
* Node.js < 9 ([node-ffi does not build with NodeJS 9.x on Linux · Issue #451 · node-ffi/node-ffi](https://github.com/node-ffi/node-ffi/issues/451))
7-
* Python 2 ([Support for Python 3 · Issue #1337 · nodejs/node-gyp](https://github.com/nodejs/node-gyp/issues/1337))
86
* SDL2
97

108

119
### Set up
1210

13-
1. Set up Node.js < 9, and Python 2.x
14-
2. Install SDL2
11+
1. Install SDL2
1512

1613
, then
1714

nodejs/package.json

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,23 +5,24 @@
55
"main": "nesemu.js",
66
"scripts": {
77
"start": "npm run build",
8-
"build": "webpack",
9-
"exec": "node nesemu.js",
8+
"build": "npx webpack",
9+
"exec": "npx node nesemu.js",
1010
"test": "echo \"Error: no test specified\" && exit 1"
1111
},
1212
"author": "tyfkda",
1313
"license": "Unlicense",
1414
"devDependencies": {
15-
"babel-core": "~6.26.3",
16-
"babel-loader": "~8.0.2",
17-
"babel-preset-env": "~1.7.0",
18-
"ts-loader": "~5.2.1",
19-
"typescript": "~3.1.1",
20-
"webpack": "~4.20.2",
21-
"webpack-cli": "~3.1.2"
15+
"@babel/core": "~7.21.8",
16+
"@babel/preset-env": "~7.21.5",
17+
"@babel/register": "~7.21.0",
18+
"@types/node": "~18.16.3",
19+
"ts-loader": "~9.4.2",
20+
"typescript": "~5.0.4",
21+
"webpack": "~5.82.0",
22+
"webpack-cli": "~5.0.2"
2223
},
2324
"dependencies": {
24-
"jszip": "~3.1.3",
25-
"node-sdl2": "git+https://github.com/tyfkda/node-sdl2.git#master"
25+
"@kmamal/sdl": "~0.7.4",
26+
"jszip": "~3.10.1"
2627
}
2728
}

nodejs/src/@types/audio_context/index.d.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
declare function __non_webpack_require__(fn: string)
2+
13
interface AudioNode {
24
readonly context: AudioContext
35

@@ -30,14 +32,16 @@ interface DelayNode extends AudioNode {
3032
delayTime: AudioParam
3133
}
3234

35+
interface ScriptProcessorNode extends AudioNode {
36+
onaudioprocess: Function
37+
}
38+
3339
interface AudioDestinationNode extends AudioNode {
3440
}
3541

3642
interface AnalyserNode extends AudioNode {
3743
}
3844

39-
type ScriptProcessorNode = any
40-
declare const ScriptProcessorNode: ScriptProcessorNode
4145
type AudioWorkletNode = any
4246
declare const AudioWorkletNode: AudioWorkletNode
4347

@@ -53,4 +57,7 @@ interface AudioContext {
5357
createDelay(): DelayNode
5458
createAnalyser(): AnalyserNode
5559
createScriptProcessor(size: number, a: number, b: number): ScriptProcessorNode
60+
61+
// Additional method:
62+
update(dt: number): void
5663
}

nodejs/src/audio_context.ts

Lines changed: 74 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,4 @@
1-
declare function __non_webpack_require__(fn: string)
2-
3-
import {audio as SDLAudio} from 'node-sdl2/lib/audio'
4-
5-
const NS = __non_webpack_require__('node-sdl2')
6-
const SDL_audio = NS.require('SDL_audio')
1+
const sdl = __non_webpack_require__('@kmamal/sdl')
72

83
class AudioParam {
94
public value = 0
@@ -44,8 +39,6 @@ export class PeriodicWave {
4439

4540
const enum OscillatorType {
4641
NONE,
47-
// SQUARE,
48-
// SINE
4942
TRIANGLE,
5043
SAWTOOTH,
5144
PERIODIC_WAVE,
@@ -66,8 +59,11 @@ export class OscillatorNode extends AudioNode {
6659
}
6760

6861
setPeriodicWave(_wave: PeriodicWave): void {
69-
this.oscType = OscillatorType.PERIODIC_WAVE
62+
// this.oscType = OscillatorType.PERIODIC_WAVE
7063
//this.wave = wave
64+
65+
// TODO: Calculate wave.
66+
this.oscType = OscillatorType.TRIANGLE
7167
}
7268

7369
public sample(counter: number, sampleRate: number): number {
@@ -119,8 +115,65 @@ export class DelayNode extends AudioNode {
119115
}
120116
}
121117

118+
class OutputBuffer<T> {
119+
constructor(public buffer: T[]) {}
120+
121+
public getChannelData(index: number) {
122+
return this.buffer[index]
123+
}
124+
}
125+
126+
export class ScriptProcessorNode extends AudioNode {
127+
private index = 0
128+
private onaudioprocess: any = (_) => {}
129+
private outputBuffer: OutputBuffer<Float32Array>
130+
private ev: {outputBuffer: OutputBuffer<Float32Array>}
131+
132+
public constructor(context: AudioContext, size: number, _inputChannels: number, outputChannels: number) {
133+
super(context)
134+
const buffer = [...Array(outputChannels)].map(_ => new Float32Array(size))
135+
this.outputBuffer = new OutputBuffer<Float32Array>(buffer)
136+
this.ev = {
137+
outputBuffer: this.outputBuffer,
138+
}
139+
}
140+
141+
public sample(_counter: number, _sampleRate: number): number {
142+
if (this.index === 0) {
143+
this.onaudioprocess(this.ev)
144+
}
145+
const value = this.outputBuffer.buffer[0][this.index]
146+
if (++this.index >= this.outputBuffer.buffer[0].length) {
147+
this.index = 0
148+
}
149+
return value
150+
}
151+
}
152+
122153
class AudioDestinationNode extends AudioNode {
123154
private time = 0
155+
private playbackInstance: any
156+
private buffer: Buffer
157+
private f32Array: Float32Array
158+
159+
public constructor(context: AudioContext) {
160+
super(context)
161+
const channels = 1
162+
this.playbackInstance = sdl.audio.openDevice({type: 'playback'}, {
163+
channels,
164+
buffered: 512,
165+
})
166+
167+
const frames = (1.0 / 60 * this.sampleRate) | 0
168+
this.buffer = Buffer.alloc(frames * 4 * channels)
169+
this.f32Array = new Float32Array(this.buffer.buffer)
170+
171+
this.playbackInstance.play()
172+
}
173+
174+
public get sampleRate(): number {
175+
return this.playbackInstance.frequency
176+
}
124177

125178
public fillBuffer(array: Float32Array) {
126179
const len = array.length
@@ -142,28 +195,22 @@ class AudioDestinationNode extends AudioNode {
142195
public sample(_counter: number, _sampleRate: number): number {
143196
return 0
144197
}
198+
199+
public update(_dt: number) {
200+
this.fillBuffer(this.f32Array)
201+
this.playbackInstance.enqueue(this.buffer)
202+
}
145203
}
146204

147205
export class AudioContext {
148-
private audio: SDLAudio
149206
private destination = new AudioDestinationNode(this)
150207

151208
public get sampleRate(): number {
152-
return this.audio.spec.freq
209+
return this.destination.sampleRate
153210
}
154211

155-
public constructor() {
156-
this.audio = NS.audio.create()
157-
const options = {
158-
freq: 48000,
159-
channels: 1,
160-
format: SDL_audio.SDL_AudioFormatFlag.AUDIO_F32,
161-
samples: 512,
162-
}
163-
this.audio.openAudioDevice(options, (arrayBuffer: ArrayBuffer) => {
164-
const array = new Float32Array(arrayBuffer)
165-
this.destination.fillBuffer(array)
166-
})
212+
public update(dt: number): void {
213+
this.destination.update(dt)
167214
}
168215

169216
public createGain(): GainNode {
@@ -178,6 +225,10 @@ export class AudioContext {
178225
return new DelayNode(this)
179226
}
180227

228+
public createScriptProcessor(size: number, a: number, b: number): ScriptProcessorNode {
229+
return new ScriptProcessorNode(this, size, a, b)
230+
}
231+
181232
public createPeriodicWave(real: Float32Array, imag: Float32Array): PeriodicWave {
182233
return new PeriodicWave(real, imag)
183234
}

0 commit comments

Comments
 (0)