mirror of
https://github.com/sehugg/8bitworkshop.git
synced 2024-11-26 10:49:17 +00:00
sound_williams: refactored into Machine
This commit is contained in:
parent
f3138f9b57
commit
5c98c2eb7d
@ -480,9 +480,8 @@ export var SampleAudio = function(clockfreq) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.feedSample = function(value, count) {
|
this.feedSample = function(value, count) {
|
||||||
while (count-- > 0) {
|
accum += value * count;
|
||||||
accum += value;
|
sfrac += sinc * count;
|
||||||
sfrac += sinc;
|
|
||||||
while (sfrac >= 1) {
|
while (sfrac >= 1) {
|
||||||
sfrac -= 1;
|
sfrac -= 1;
|
||||||
value *= sfrac;
|
value *= sfrac;
|
||||||
@ -490,7 +489,6 @@ export var SampleAudio = function(clockfreq) {
|
|||||||
accum = value;
|
accum = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3408,6 +3408,9 @@ export class Z80 implements CPU, InstructionBased, IOBusConnected, SavesState<Z8
|
|||||||
getPC() {
|
getPC() {
|
||||||
return this.cpu.getPC();
|
return this.cpu.getPC();
|
||||||
}
|
}
|
||||||
|
isHalted() {
|
||||||
|
return this.cpu.getHalted();
|
||||||
|
}
|
||||||
saveState() {
|
saveState() {
|
||||||
return this.cpu.saveState();
|
return this.cpu.saveState();
|
||||||
}
|
}
|
||||||
|
@ -305,11 +305,6 @@ export abstract class BasicMachine implements HasCPU, Bus, SampledAudioSource, A
|
|||||||
inputs:this.inputs.slice(0)
|
inputs:this.inputs.slice(0)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
advanceCPUMultiple(cycles : number) : number {
|
|
||||||
for (var i=0; i<cycles; i+=this.advanceCPU())
|
|
||||||
;
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
advanceCPU() {
|
advanceCPU() {
|
||||||
var c = this.cpu as any;
|
var c = this.cpu as any;
|
||||||
var n = 1;
|
var n = 1;
|
||||||
|
@ -1,8 +1,9 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
import { Platform, BaseZ80Platform } from "../baseplatform";
|
import { Z80, Z80State } from "../cpu/ZilogZ80";
|
||||||
|
import { BasicMachine, CPU, Bus } from "../devices";
|
||||||
|
import { Platform, BaseZ80MachinePlatform } from "../baseplatform";
|
||||||
import { PLATFORMS, RAM, newAddressDecoder, padBytes, noise, setKeyboardFromMap, AnimationTimer, RasterVideo, Keys, makeKeycodeMap } from "../emu";
|
import { PLATFORMS, RAM, newAddressDecoder, padBytes, noise, setKeyboardFromMap, AnimationTimer, RasterVideo, Keys, makeKeycodeMap } from "../emu";
|
||||||
import { hex } from "../util";
|
|
||||||
import { SampleAudio } from "../audio";
|
import { SampleAudio } from "../audio";
|
||||||
|
|
||||||
var WILLIAMS_SOUND_PRESETS = [
|
var WILLIAMS_SOUND_PRESETS = [
|
||||||
@ -33,126 +34,89 @@ var WILLIAMS_SOUND_PRESETS = [
|
|||||||
|
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
var WilliamsSoundPlatform = function(mainElement) {
|
class WilliamsSound extends BasicMachine {
|
||||||
var self = this;
|
cpuFrequency = 18432000 / 6; // 3.072 MHz
|
||||||
this.__proto__ = new (BaseZ80Platform as any)();
|
cpuCyclesPerFrame = this.cpuFrequency / 60;
|
||||||
|
cpuAudioFactor = 32;
|
||||||
|
canvasWidth = 256;
|
||||||
|
numVisibleScanlines = 256;
|
||||||
|
defaultROMSize = 0x4000;
|
||||||
|
sampleRate = this.cpuFrequency;
|
||||||
|
overscan = true;
|
||||||
|
|
||||||
var cpu, ram, rom, membus, iobus;
|
cpu : Z80;
|
||||||
var audio, master;
|
ram = new Uint8Array(0x400);
|
||||||
var video, timer;
|
iobus : Bus;
|
||||||
var command = 0;
|
|
||||||
var dac = 0;
|
|
||||||
var dac_float = 0.0
|
|
||||||
var current_buffer;
|
|
||||||
var last_tstate = 0;
|
|
||||||
var tstates = 0;
|
|
||||||
var pixels;
|
|
||||||
|
|
||||||
var cpuFrequency = 18432000 / 6; // 3.072 MHz
|
command : number = 0;
|
||||||
var cpuCyclesPerFrame = cpuFrequency / 60;
|
dac : number = 0;
|
||||||
var cpuAudioFactor = 32;
|
dac_float : number = 0;
|
||||||
|
xpos : number = 0;
|
||||||
|
|
||||||
function fillBuffer() {
|
read = newAddressDecoder([
|
||||||
var t = tstates / cpuAudioFactor;
|
[0x0000, 0x3fff, 0x3fff, (a) => { return this.rom && this.rom[a]; }],
|
||||||
while (last_tstate < t) {
|
[0x4000, 0x7fff, 0x3ff, (a) => { return this.ram[a]; }]
|
||||||
current_buffer[last_tstate++] = dac_float;
|
]);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.getPresets = function() {
|
write = newAddressDecoder([
|
||||||
return WILLIAMS_SOUND_PRESETS;
|
[0x4000, 0x7fff, 0x3ff, (a, v) => { this.ram[a] = v; }],
|
||||||
}
|
]);
|
||||||
|
|
||||||
this.start = function() {
|
constructor() {
|
||||||
ram = new RAM(0x400);
|
super();
|
||||||
membus = {
|
this.cpu = new Z80();
|
||||||
read: newAddressDecoder([
|
this.connectCPUMemoryBus(this);
|
||||||
[0x0000, 0x3fff, 0x3fff, function(a) { return rom ? rom[a] : null; }],
|
this.connectCPUIOBus({
|
||||||
[0x4000, 0x7fff, 0x3ff, function(a) { return ram.mem[a]; }]
|
read: (addr) => {
|
||||||
]),
|
return this.command & 0xff;
|
||||||
write: newAddressDecoder([
|
|
||||||
[0x4000, 0x7fff, 0x3ff, function(a, v) { ram.mem[a] = v; }],
|
|
||||||
]),
|
|
||||||
};
|
|
||||||
iobus = {
|
|
||||||
read: function(addr) {
|
|
||||||
return command & 0xff;
|
|
||||||
},
|
},
|
||||||
write: function(addr, val) {
|
write: (addr, val) => {
|
||||||
dac = val & 0xff;
|
let dac = this.dac = val & 0xff;
|
||||||
dac_float = ((dac & 0x80) ? -256 + dac : dac) / 128.0;
|
this.dac_float = ((dac & 0x80) ? -256 + dac : dac) / 128.0;
|
||||||
fillBuffer();
|
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
this.readAddress = membus.read;
|
|
||||||
cpu = this.newCPU(membus, iobus);
|
|
||||||
audio = new SampleAudio(cpuFrequency / cpuAudioFactor);
|
|
||||||
audio.callback = function(lbuf) {
|
|
||||||
if (self.isRunning()) {
|
|
||||||
current_buffer = lbuf;
|
|
||||||
last_tstate = 0;
|
|
||||||
tstates = 0;
|
|
||||||
while (tstates < lbuf.length * cpuAudioFactor) {
|
|
||||||
tstates += self.runCPU(cpu, 1);
|
|
||||||
}
|
}
|
||||||
fillBuffer();
|
|
||||||
for (var i = 0; i < 256; i++) {
|
advanceFrame(maxCycles, trap) : number {
|
||||||
var y = Math.round((current_buffer[i] * 127) + 128);
|
this.pixels && this.pixels.fill(0); // clear waveform
|
||||||
pixels[i + y * 256] = 0xff33ff33;
|
maxCycles = Math.min(this.cpuCyclesPerFrame, maxCycles);
|
||||||
|
var n = 0;
|
||||||
|
while (n < maxCycles) {
|
||||||
|
if (trap && trap()) {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
n += this.advanceCPU();
|
||||||
}
|
}
|
||||||
};
|
return n;
|
||||||
video = new RasterVideo(mainElement, 256, 256);
|
}
|
||||||
video.create();
|
|
||||||
video.setKeyboardEvents(function(key, code, flags) {
|
advanceCPU() {
|
||||||
|
var n = super.advanceCPU();
|
||||||
|
this.audio && this.audio.feedSample(this.dac_float, n);
|
||||||
|
// draw waveform on screen
|
||||||
|
if (this.pixels && !this.cpu.isHalted()) {
|
||||||
|
this.pixels[((this.xpos >> 8) & 0xff) + ((255-this.dac) << 8)] = 0xff33ff33;
|
||||||
|
this.xpos = (this.xpos + n) & 0xffffff;
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
setKeyInput(key:number, code:number, flags:number) : void {
|
||||||
var intr = (key - 49);
|
var intr = (key - 49);
|
||||||
if (intr >= 0 && (flags & 1)) {
|
if (intr >= 0 && (flags & 1)) {
|
||||||
command = intr & 0xff;
|
this.command = intr & 0xff;
|
||||||
cpu.reset();
|
this.cpu.reset();
|
||||||
}
|
}
|
||||||
});
|
|
||||||
pixels = video.getFrameData();
|
|
||||||
timer = new AnimationTimer(30, function() {
|
|
||||||
if (self.isRunning()) {
|
|
||||||
video.updateFrame();
|
|
||||||
pixels.fill(0);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.loadROM = function(title, data) {
|
|
||||||
rom = padBytes(data, 0x4000);
|
|
||||||
cpu.reset();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.loadState = function(state) {
|
|
||||||
cpu.loadState(state.c);
|
|
||||||
ram.mem.set(state.b);
|
|
||||||
}
|
|
||||||
this.saveState = function() {
|
|
||||||
return {
|
|
||||||
c: self.getCPUState(),
|
|
||||||
b: ram.mem.slice(0),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
this.getCPUState = function() {
|
|
||||||
return cpu.saveState();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.isRunning = function() {
|
|
||||||
return timer && timer.isRunning();
|
|
||||||
}
|
|
||||||
this.pause = function() {
|
|
||||||
timer.stop();
|
|
||||||
audio.stop();
|
|
||||||
}
|
|
||||||
this.resume = function() {
|
|
||||||
timer.start();
|
|
||||||
audio.start();
|
|
||||||
}
|
|
||||||
this.reset = function() {
|
|
||||||
cpu.reset();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class WilliamsSoundPlatform extends BaseZ80MachinePlatform<WilliamsSound> {
|
||||||
|
|
||||||
|
newMachine() { return new WilliamsSound(); }
|
||||||
|
getPresets() { return WILLIAMS_SOUND_PRESETS; }
|
||||||
|
getDefaultExtension() { return ".c"; };
|
||||||
|
readAddress(a) { return this.machine.read(a); }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
PLATFORMS['sound_williams-z80'] = WilliamsSoundPlatform;
|
PLATFORMS['sound_williams-z80'] = WilliamsSoundPlatform;
|
||||||
|
@ -262,7 +262,6 @@ describe('Platform Replay', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
/*
|
|
||||||
it('Should run sound_williams', () => {
|
it('Should run sound_williams', () => {
|
||||||
var platform = testPlatform('sound_williams-z80', 'swave.c.rom', 72, (platform, frameno) => {
|
var platform = testPlatform('sound_williams-z80', 'swave.c.rom', 72, (platform, frameno) => {
|
||||||
if (frameno == 60) {
|
if (frameno == 60) {
|
||||||
@ -270,7 +269,6 @@ describe('Platform Replay', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
*/
|
|
||||||
|
|
||||||
it('Should run astrocade', () => {
|
it('Should run astrocade', () => {
|
||||||
var platform = testPlatform('astrocade', 'cosmic.c.rom', 92, (platform, frameno) => {
|
var platform = testPlatform('astrocade', 'cosmic.c.rom', 92, (platform, frameno) => {
|
||||||
|
Loading…
Reference in New Issue
Block a user