diff vgm.c @ 1909:508522f08e4d

Initial stab at VGM logging support
author Michael Pavone <pavone@retrodev.com>
date Fri, 27 Mar 2020 00:03:58 -0700
parents
children a9449608d0b0
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vgm.c	Fri Mar 27 00:03:58 2020 -0700
@@ -0,0 +1,117 @@
+#include <stdlib.h>
+#include <string.h>
+#include <stddef.h>
+#include "vgm.h"
+
+vgm_writer *vgm_write_open(char *filename, uint32_t rate, uint32_t clock, uint32_t cycle)
+{
+	FILE *f = fopen(filename, "wb");
+	if (!f) {
+		return NULL;
+	}
+	vgm_writer *writer = calloc(sizeof(vgm_writer), 1);
+	memcpy(writer->header.ident, "Vgm ", 4);
+	writer->header.version = 0x150;
+	writer->header.data_offset = sizeof(writer->header) - offsetof(vgm_header, data_offset);
+	writer->header.rate = rate;
+	writer->f = f;
+	if (1 != fwrite(&writer->header, sizeof(writer->header), 1, f)) {
+		free(writer);
+		fclose(f);
+		return NULL;
+	}
+	writer->master_clock = clock;
+	writer->last_cycle = cycle;
+	
+	return writer;
+}
+
+void vgm_sn76489_init(vgm_writer *writer, uint32_t clock, uint16_t feedback, uint8_t shift_reg_size, uint8_t flags)
+{
+	if (flags && writer->header.version < 0x151) {
+		writer->header.version = 0x151;
+	}
+	writer->header.sn76489_clk = clock,
+	writer->header.sn76489_fb = feedback;
+	writer->header.sn76489_shift = shift_reg_size;
+	writer->header.sn76489_flags = flags;
+}
+
+static void wait_commands(vgm_writer *writer, uint32_t delta)
+{
+	if (!delta) {
+		return;
+	}
+	if (delta <= 0x10) {
+		fputc(CMD_WAIT_SHORT + (delta - 1), writer->f);
+	} else if (delta >= 735 && delta <= (735 + 0x10)) {
+		fputc(CMD_WAIT_60, writer->f);
+		wait_commands(writer, delta - 735);
+	} else if (delta >= 882 && delta <= (882 + 0x10)) {
+		fputc(CMD_WAIT_50, writer->f);
+		wait_commands(writer, delta - 882);
+	} else if (delta > 0xFFFF) {
+		uint8_t cmd[3] = {CMD_WAIT, 0xFF, 0xFF};
+		fwrite(cmd, 1, sizeof(cmd), writer->f);
+		wait_commands(writer, delta - 0xFFFF);
+	} else {
+		uint8_t cmd[3] = {CMD_WAIT, delta, delta >> 8};
+		fwrite(cmd, 1, sizeof(cmd), writer->f);
+	}
+}
+
+static void add_wait(vgm_writer *writer, uint32_t cycle)
+{
+	uint64_t delta = cycle - writer->last_cycle;
+	delta *= (uint64_t)44100;
+	delta /= (uint64_t)writer->master_clock;
+	
+	uint32_t mclks_per_sample = writer->master_clock / 44100;
+	writer->last_cycle += delta * mclks_per_sample; 
+	writer->header.num_samples += delta;
+	wait_commands(writer, delta);
+}
+
+void vgm_sn76489_write(vgm_writer *writer, uint32_t cycle, uint8_t value)
+{
+	add_wait(writer, cycle);
+	uint8_t cmd[2] = {CMD_PSG, value};
+	fwrite(cmd, 1, sizeof(cmd), writer->f);
+}
+
+void vgm_ym2612_init(vgm_writer *writer, uint32_t clock)
+{
+	writer->header.ym2612_clk = clock;
+}
+
+void vgm_ym2612_part1_write(vgm_writer *writer, uint32_t cycle, uint8_t reg, uint8_t value)
+{
+	add_wait(writer, cycle);
+	uint8_t cmd[3] = {CMD_YM2612_0, reg, value};
+	fwrite(cmd, 1, sizeof(cmd), writer->f);
+}
+
+void vgm_ym2612_part2_write(vgm_writer *writer, uint32_t cycle, uint8_t reg, uint8_t value)
+{
+	add_wait(writer, cycle);
+	uint8_t cmd[3] = {CMD_YM2612_1, reg, value};
+	fwrite(cmd, 1, sizeof(cmd), writer->f);
+}
+
+void vgm_adjust_cycles(vgm_writer *writer, uint32_t deduction)
+{
+	if (deduction > writer->last_cycle) {
+		writer->last_cycle = 0;
+	} else {
+		writer->last_cycle -= deduction;
+	}
+}
+
+void vgm_close(vgm_writer *writer)
+{
+	writer->header.eof_offset = ftell(writer->f) - offsetof(vgm_header, eof_offset);
+	fseek(writer->f, SEEK_SET, 0);
+	fwrite(&writer->header, sizeof(writer->header), 1, writer->f);
+	fclose(writer->f);
+	free(writer);
+}
\ No newline at end of file