sound_williams: refactored into Machine

This commit is contained in:
Steven Hugg 2019-08-31 15:36:58 -04:00
parent f3138f9b57
commit 5c98c2eb7d
5 changed files with 87 additions and 129 deletions

View File

@ -480,15 +480,13 @@ export var SampleAudio = function(clockfreq) {
}
this.feedSample = function(value, count) {
while (count-- > 0) {
accum += value;
sfrac += sinc;
while (sfrac >= 1) {
sfrac -= 1;
value *= sfrac;
this.addSingleSample(accum - value);
accum = value;
}
accum += value * count;
sfrac += sinc * count;
while (sfrac >= 1) {
sfrac -= 1;
value *= sfrac;
this.addSingleSample(accum - value);
accum = value;
}
}

View File

@ -3408,6 +3408,9 @@ export class Z80 implements CPU, InstructionBased, IOBusConnected, SavesState<Z8
getPC() {
return this.cpu.getPC();
}
isHalted() {
return this.cpu.getHalted();
}
saveState() {
return this.cpu.saveState();
}

View File

@ -305,11 +305,6 @@ export abstract class BasicMachine implements HasCPU, Bus, SampledAudioSource, A
inputs:this.inputs.slice(0)
};
}
advanceCPUMultiple(cycles : number) : number {
for (var i=0; i<cycles; i+=this.advanceCPU())
;
return i;
}
advanceCPU() {
var c = this.cpu as any;
var n = 1;

View File

@ -1,8 +1,9 @@
"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 { hex } from "../util";
import { SampleAudio } from "../audio";
var WILLIAMS_SOUND_PRESETS = [
@ -33,126 +34,89 @@ var WILLIAMS_SOUND_PRESETS = [
****************************************************************************/
var WilliamsSoundPlatform = function(mainElement) {
var self = this;
this.__proto__ = new (BaseZ80Platform as any)();
class WilliamsSound extends BasicMachine {
cpuFrequency = 18432000 / 6; // 3.072 MHz
cpuCyclesPerFrame = this.cpuFrequency / 60;
cpuAudioFactor = 32;
canvasWidth = 256;
numVisibleScanlines = 256;
defaultROMSize = 0x4000;
sampleRate = this.cpuFrequency;
overscan = true;
cpu : Z80;
ram = new Uint8Array(0x400);
iobus : Bus;
command : number = 0;
dac : number = 0;
dac_float : number = 0;
xpos : number = 0;
var cpu, ram, rom, membus, iobus;
var audio, master;
var video, timer;
var command = 0;
var dac = 0;
var dac_float = 0.0
var current_buffer;
var last_tstate = 0;
var tstates = 0;
var pixels;
read = newAddressDecoder([
[0x0000, 0x3fff, 0x3fff, (a) => { return this.rom && this.rom[a]; }],
[0x4000, 0x7fff, 0x3ff, (a) => { return this.ram[a]; }]
]);
var cpuFrequency = 18432000 / 6; // 3.072 MHz
var cpuCyclesPerFrame = cpuFrequency / 60;
var cpuAudioFactor = 32;
function fillBuffer() {
var t = tstates / cpuAudioFactor;
while (last_tstate < t) {
current_buffer[last_tstate++] = dac_float;
}
}
this.getPresets = function() {
return WILLIAMS_SOUND_PRESETS;
}
this.start = function() {
ram = new RAM(0x400);
membus = {
read: newAddressDecoder([
[0x0000, 0x3fff, 0x3fff, function(a) { return rom ? rom[a] : null; }],
[0x4000, 0x7fff, 0x3ff, function(a) { return ram.mem[a]; }]
]),
write: newAddressDecoder([
[0x4000, 0x7fff, 0x3ff, function(a, v) { ram.mem[a] = v; }],
]),
};
iobus = {
read: function(addr) {
return command & 0xff;
write = newAddressDecoder([
[0x4000, 0x7fff, 0x3ff, (a, v) => { this.ram[a] = v; }],
]);
constructor() {
super();
this.cpu = new Z80();
this.connectCPUMemoryBus(this);
this.connectCPUIOBus({
read: (addr) => {
return this.command & 0xff;
},
write: function(addr, val) {
dac = val & 0xff;
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++) {
var y = Math.round((current_buffer[i] * 127) + 128);
pixels[i + y * 256] = 0xff33ff33;
}
}
};
video = new RasterVideo(mainElement, 256, 256);
video.create();
video.setKeyboardEvents(function(key, code, flags) {
var intr = (key - 49);
if (intr >= 0 && (flags & 1)) {
command = intr & 0xff;
cpu.reset();
}
});
pixels = video.getFrameData();
timer = new AnimationTimer(30, function() {
if (self.isRunning()) {
video.updateFrame();
pixels.fill(0);
write: (addr, val) => {
let dac = this.dac = val & 0xff;
this.dac_float = ((dac & 0x80) ? -256 + dac : dac) / 128.0;
}
});
}
this.loadROM = function(title, data) {
rom = padBytes(data, 0x4000);
cpu.reset();
advanceFrame(maxCycles, trap) : number {
this.pixels && this.pixels.fill(0); // clear waveform
maxCycles = Math.min(this.cpuCyclesPerFrame, maxCycles);
var n = 0;
while (n < maxCycles) {
if (trap && trap()) {
break;
}
n += this.advanceCPU();
}
return n;
}
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;
}
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();
setKeyInput(key:number, code:number, flags:number) : void {
var intr = (key - 49);
if (intr >= 0 && (flags & 1)) {
this.command = intr & 0xff;
this.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;

View File

@ -262,7 +262,6 @@ describe('Platform Replay', () => {
}
});
});
/*
it('Should run sound_williams', () => {
var platform = testPlatform('sound_williams-z80', 'swave.c.rom', 72, (platform, frameno) => {
if (frameno == 60) {
@ -270,7 +269,6 @@ describe('Platform Replay', () => {
}
});
});
*/
it('Should run astrocade', () => {
var platform = testPlatform('astrocade', 'cosmic.c.rom', 92, (platform, frameno) => {