comparison 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
comparison
equal deleted inserted replaced
1908:c3d49c338224 1909:508522f08e4d
1 #include <stdlib.h>
2 #include <string.h>
3 #include <stddef.h>
4 #include "vgm.h"
5
6 vgm_writer *vgm_write_open(char *filename, uint32_t rate, uint32_t clock, uint32_t cycle)
7 {
8 FILE *f = fopen(filename, "wb");
9 if (!f) {
10 return NULL;
11 }
12 vgm_writer *writer = calloc(sizeof(vgm_writer), 1);
13 memcpy(writer->header.ident, "Vgm ", 4);
14 writer->header.version = 0x150;
15 writer->header.data_offset = sizeof(writer->header) - offsetof(vgm_header, data_offset);
16 writer->header.rate = rate;
17 writer->f = f;
18 if (1 != fwrite(&writer->header, sizeof(writer->header), 1, f)) {
19 free(writer);
20 fclose(f);
21 return NULL;
22 }
23 writer->master_clock = clock;
24 writer->last_cycle = cycle;
25
26 return writer;
27 }
28
29 void vgm_sn76489_init(vgm_writer *writer, uint32_t clock, uint16_t feedback, uint8_t shift_reg_size, uint8_t flags)
30 {
31 if (flags && writer->header.version < 0x151) {
32 writer->header.version = 0x151;
33 }
34 writer->header.sn76489_clk = clock,
35 writer->header.sn76489_fb = feedback;
36 writer->header.sn76489_shift = shift_reg_size;
37 writer->header.sn76489_flags = flags;
38 }
39
40 static void wait_commands(vgm_writer *writer, uint32_t delta)
41 {
42 if (!delta) {
43 return;
44 }
45 if (delta <= 0x10) {
46 fputc(CMD_WAIT_SHORT + (delta - 1), writer->f);
47 } else if (delta >= 735 && delta <= (735 + 0x10)) {
48 fputc(CMD_WAIT_60, writer->f);
49 wait_commands(writer, delta - 735);
50 } else if (delta >= 882 && delta <= (882 + 0x10)) {
51 fputc(CMD_WAIT_50, writer->f);
52 wait_commands(writer, delta - 882);
53 } else if (delta > 0xFFFF) {
54 uint8_t cmd[3] = {CMD_WAIT, 0xFF, 0xFF};
55 fwrite(cmd, 1, sizeof(cmd), writer->f);
56 wait_commands(writer, delta - 0xFFFF);
57 } else {
58 uint8_t cmd[3] = {CMD_WAIT, delta, delta >> 8};
59 fwrite(cmd, 1, sizeof(cmd), writer->f);
60 }
61 }
62
63 static void add_wait(vgm_writer *writer, uint32_t cycle)
64 {
65 uint64_t delta = cycle - writer->last_cycle;
66 delta *= (uint64_t)44100;
67 delta /= (uint64_t)writer->master_clock;
68
69 uint32_t mclks_per_sample = writer->master_clock / 44100;
70 writer->last_cycle += delta * mclks_per_sample;
71 writer->header.num_samples += delta;
72 wait_commands(writer, delta);
73 }
74
75 void vgm_sn76489_write(vgm_writer *writer, uint32_t cycle, uint8_t value)
76 {
77 add_wait(writer, cycle);
78 uint8_t cmd[2] = {CMD_PSG, value};
79 fwrite(cmd, 1, sizeof(cmd), writer->f);
80 }
81
82 void vgm_ym2612_init(vgm_writer *writer, uint32_t clock)
83 {
84 writer->header.ym2612_clk = clock;
85 }
86
87 void vgm_ym2612_part1_write(vgm_writer *writer, uint32_t cycle, uint8_t reg, uint8_t value)
88 {
89 add_wait(writer, cycle);
90 uint8_t cmd[3] = {CMD_YM2612_0, reg, value};
91 fwrite(cmd, 1, sizeof(cmd), writer->f);
92 }
93
94 void vgm_ym2612_part2_write(vgm_writer *writer, uint32_t cycle, uint8_t reg, uint8_t value)
95 {
96 add_wait(writer, cycle);
97 uint8_t cmd[3] = {CMD_YM2612_1, reg, value};
98 fwrite(cmd, 1, sizeof(cmd), writer->f);
99 }
100
101 void vgm_adjust_cycles(vgm_writer *writer, uint32_t deduction)
102 {
103 if (deduction > writer->last_cycle) {
104 writer->last_cycle = 0;
105 } else {
106 writer->last_cycle -= deduction;
107 }
108 }
109
110 void vgm_close(vgm_writer *writer)
111 {
112 writer->header.eof_offset = ftell(writer->f) - offsetof(vgm_header, eof_offset);
113 fseek(writer->f, SEEK_SET, 0);
114 fwrite(&writer->header, sizeof(writer->header), 1, writer->f);
115 fclose(writer->f);
116 free(writer);
117 }