1
0
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:
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,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;
} }
} }
}
} }

View File

@ -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();
} }

View File

@ -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;

View File

@ -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;

View File

@ -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) => {