Mercurial > repos > blastem
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 } |